C++学习——栈(一)
文章目录
- 前言
- 一、顺序表实现栈
- 二、链表实现栈
- 三、C++STL中的栈
- 四、C++中的:和::的区别
- 1. 单冒号(:)的用法
- (1)初始化列表(构造函数)
- (2) 继承声明
- (3)访问控制符
- (4)位域(Bit-field)
- 2. 双冒号(::)的用法
- (1)作用域解析
- (2)静态成员访问
- (3)命名空间访问
- (4)全局函数调用
- 3.核心区别与注意事项
- 4.总结
前言
本文为《C++学习》的第3篇文章,今天学习栈。
一、顺序表实现栈
#include<iostream>
#include<stdexcept>
using namespace std;
template<typename T>
class Stack{
private:
T *data;
int size;
int capacity;
void resize();
public:
Stack() : data(new T[capacity]), size(0), capacity(10) {}
~Stack();
void push(T element);
T pop();
T top() const;
int getSize() const;
};
template<typename T>
void Stack<T>::resize(){
int newCapacity = capacity * 2;
T *newData = new T[newCapacity];
for(int i = 0; i < size; ++i){
newData[i] = data[i];
}
delete[] data;
data = newData;
capacity = newCapacity;
}
template<typename T>
Stack<T>::~Stack(){
delete[] data;
}
template<typename T>
void Stack<T>::push(T element){
if(size == capacity){
resize();
}
data[size++] = element;
}
template<typename T>
T Stack<T>::pop(){
if(size == 0){
throw std::underflow_error("Stack is empty");
}
return data[--size];
}
template<typename T>
T Stack<T>::top() const{
if(size == 0){
throw std::underflow_error("Stack is empty");
}
return data[size-1];
}
template<typename T>
int Stack<T>::getSize() const{
return size;
}
int main(){
Stack<int> myst;
myst.push(12);
myst.push(23);
myst.push(34);
cout << myst.top() << endl;
myst.push(45);
cout << myst.top() << endl;
myst.pop();
myst.pop();
cout << myst.top() << endl;
cout << myst.getSize() << endl;
return 0;
}
二、链表实现栈
#include<iostream>
#include<stdexcept>
using namespace std;
template<typename T>
class Stack{
private:
struct Node{
T data;
Node *next;
Node(T d) : data(d), next(NULL) {}//在构造函数后使用单冒号,用于初始化类的成员变量
};
Node *head;
int size;
public:
Stack() : head(NULL), size(0) {}
~Stack();
void push(T element);
T pop();
T top() const;
int getSize() const;
};
template<typename T>
Stack<T>::~Stack(){
while(head){
Node *temp = head;
head = head->next;
delete temp;
}
}
template<typename T>
void Stack<T>::push(T element){
Node *newNode = new Node(element);
newNode->next = head;
head = newNode;
++size;
}
template<typename T>
T Stack<T>::pop(){
if(head == NULL){
throw std::underflow_error("Stack is empty");
}
T result = head->data;
Node *temp = head;
head = head->next;
delete temp;
return result;
}
template<typename T>
T Stack<T>::top() const{
if(head == NULL){
throw std::underflow_error("Stack is empty");
}
return head->data;
}
template<typename T>
int Stack<T>::getSize() const{
return size;
}
int main(){
Stack<int> myst;
myst.push(12);
myst.push(23);
myst.push(34);
cout << myst.top() << endl;
myst.push(45);
cout << myst.top() << endl;
myst.pop();
myst.pop();
cout << myst.top() << endl;
cout << myst.getSize() << endl;
return 0;
}
三、C++STL中的栈
#include<iostream>
#include<stack>
using namespace std;
/*
我们只需要记住四个常用的接口就好
判空;empty()
入栈:push(value)
出栈:pop()
取顶:top()
*/
int main(){
stack<int> intstack;
stack<double> doublestack;
intstack.push(11);
intstack.push(22);
intstack.push(33);
intstack.push(44);
while(!intstack.empty()){
cout << intstack.top() << " ";
intstack.pop();
}
cout << endl;
doublestack.push(1.1);
doublestack.push(2.2);
doublestack.push(3.3);
doublestack.push(4.4);
while(!doublestack.empty()){
cout << doublestack.top() << " ";
doublestack.pop();
}
cout << endl;
return 0;
}
四、C++中的:和::的区别
我们在这篇文章的末尾补充一个小问题,总结一下C++中的单冒号:和双冒号::的区别,这些区别大家不需要刻意去记,理解就行,平时在写代码的时候多留意多总结即可。
1. 单冒号(:)的用法
(1)初始化列表(构造函数)
在构造函数后使用冒号,用于初始化类的成员变量(尤其适用于const成员和引用类型):
class Test {
public:
Test(int x) : m_x(x), m_const(100) {} // 初始化列表
private:
int m_x;
const int m_const;
};
- 特点:初始化顺序与成员声明顺序一致,而非初始化列表中的顺序;
- 必要性:const成员和引用类型必须通过初始化列表赋值。
(2) 继承声明
定义派生类时,冒号后声明基类和继承方式:
class Derived : public Base { // 公有继承Base类
// 派生类成员
};
(3)访问控制符
在类中声明public:、private:或protected:,表示后续成员的访问权限:
class MyClass {
public: // 以下成员为公有
int a;
private: // 以下成员为私有
int b;
};
(4)位域(Bit-field)
在结构体或类中定义变量占用的比特位数:
struct BitField {
unsigned int a : 4; // a占4位
unsigned int b : 8; // b占8位
};
2. 双冒号(::)的用法
(1)作用域解析
访问全局作用域、类作用域或命名空间中的成员:
int global = 10;
class MyClass {
public:
static void func();
};
void MyClass::func() { // 类外定义成员函数
::global = 20; // 访问全局变量
}
(2)静态成员访问
访问类的静态成员:
class Math {
public:
static const double PI;
};
double pi = Math::PI; // 通过类名访问静态成员
(3)命名空间访问
指定命名空间内的元素:
std::cout << "Hello"; // 访问std命名空间中的cout
(4)全局函数调用
明确调用全局函数(避免与局部函数冲突):
void myFunc() { /* ... */ }
int main() {
::myFunc(); // 强制调用全局函数
}
3.核心区别与注意事项
易混淆场景示例 :
class Base {
public:
Base(int x) : m_x(x) {} // 冒号:构造函数初始化列表
};
class Derived : public Base { // 冒号:继承声明
public:
Derived() : Base(0), m_derived(0) {}
static void func();
};
void Derived::func() { // 双冒号:类外定义成员函数
::printf("Global function"); // 双冒号:调用全局函数
}
4.总结
- 冒号(:):侧重声明阶段的逻辑控制(如初始化、继承关系、权限分组);
- 双冒号(::):侧重运行时的作用域解析(如明确函数或变量的归属)。
这就是今天的全部内容了,谢谢大家的观看,不要忘了给一个免费的赞哦!