C++学习——栈(一)

文章目录


前言

本文为《C++学习》的第3篇文章,今天学习栈。


一、顺序表实现栈

cpp 复制代码
#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;
}

二、链表实现栈

cpp 复制代码
#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中的栈

cpp 复制代码
#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成员和引用类型):

cpp 复制代码
class Test {
public:
    Test(int x) : m_x(x), m_const(100) {} // 初始化列表
private:
    int m_x;
    const int m_const;
};
  • 特点:初始化顺序与成员声明顺序一致,而非初始化列表中的顺序;
  • 必要性:const成员和引用类型必须通过初始化列表赋值。

​(2) ​继承声明

定义派生类时,冒号后声明基类和继承方式:

cpp 复制代码
class Derived : public Base { // 公有继承Base类
    // 派生类成员
};

​(3)访问控制符

在类中声明public:、private:或protected:,表示后续成员的访问权限:

cpp 复制代码
class MyClass {
public:    // 以下成员为公有
    int a;
private:   // 以下成员为私有
    int b;
};

​(4)​位域(Bit-field)​

在结构体或类中定义变量占用的比特位数:

cpp 复制代码
struct BitField {
    unsigned int a : 4;  // a占4位
    unsigned int b : 8;  // b占8位
};

2. 双冒号(::)的用法

​(1)作用域解析

访问全局作用域、类作用域或命名空间中的成员:

cpp 复制代码
int global = 10;

class MyClass {
public:
    static void func();
};

void MyClass::func() { // 类外定义成员函数
    ::global = 20;     // 访问全局变量
}

​(2)静态成员访问

访问类的静态成员:

cpp 复制代码
class Math {
public:
    static const double PI;
};
double pi = Math::PI; // 通过类名访问静态成员

​(3)命名空间访问​

指定命名空间内的元素:

cpp 复制代码
std::cout << "Hello"; // 访问std命名空间中的cout

​(4)全局函数调用​

明确调用全局函数(避免与局部函数冲突):

cpp 复制代码
void myFunc() { /* ... */ }

int main() {
    ::myFunc(); // 强制调用全局函数
}

3.核心区别与注意事项


易混淆场景示例 :

cpp 复制代码
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.总结

  • 冒号(:):侧重声明阶段的逻辑控制(如初始化、继承关系、权限分组);
  • 双冒号(::):侧重运行时的作用域解析(如明确函数或变量的归属)。

这就是今天的全部内容了,谢谢大家的观看,不要忘了给一个免费的赞哦!

相关推荐
维克兜率天2 小时前
【维克】大数定律与中心极限定理:为什么长期均值终将回归?
经验分享·学习·金融·概率论
中微极客2 小时前
降维算法75倍加速:从PCA到稀疏字典学习的工程实践
人工智能·学习·算法
ziguo11223 小时前
深入浅出 C/C++ 数据类型:从入门到踩坑
linux·c语言·c++·windows·visual studio
白色冰激凌3 小时前
[SECS/GEM研究] (三)SECS-I 串口上消息怎么分块和重传
c++·secs/gem
光头闪亮亮4 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(中)
android·c++·go
光头闪亮亮4 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(下)
android·c++·go
吃好睡好便好4 小时前
MATLAB中图像的读取、写入和显示
开发语言·图像处理·学习·计算机视觉·matlab
~kiss~4 小时前
大模型中的强化学习算法和对齐算法的区别
学习
MartinYeung54 小时前
[论文学习]InjecAgent:工具集成大语言模型智能体的间接提示注入基准测试
网络·学习·语言模型
yaoxin5211234 小时前
476. Java 反射 - 调用方法
java·开发语言