【原创】【自制系列】自制stack类型(泛型)
前言
自制类型的第三篇,stack类型。stack是指栈,其实我个人认为stack是最好写的类型,没有之一。关于queue类型需要涉及到循环队列避免浪费内存,但是stack的插入删除都是对于栈顶而言,比较好写。
自制类型的主要目的,是为了练习数据结构,提高写代码的能力。
常见函数
s.empty() 判断栈s是否为空
s.size() 返回栈s的大小
s.push(a) 把a推入栈
s.pop() 弹出栈顶元素
s.top() 返回栈顶元素
泛型
我们在使用标准库的stack,是这样写的:
stack<int> stk;
使用尖括号指定类型,就是泛型的一种。如果把int改为char,甚至是结构体等,都可以。
最简单的例子:
#include<iostream>
#include<vector>
using namespace std;
int main(){
int a=5,b=10;cout<<max(a,b);
float c=3.14,d=9.99;cout<<max(c,d);
char e='x',f='*';cout<<max(e,f);
}
这里,max函数即可以处理int,又可以处理float,char类型的最大值。这就是泛型。max函数无论针对哪一个类型,操作都是相同的。因此,我们使用通用类型,让函数不关注类型只关注具体的操作。
有人会问,其实使用函数重载不就能完成了吗?但是,函数重载要重复写好几次,不方便。
泛型的函数,可以使用template关键字写:
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
T MAX(T a,T b){
if(a>b)return a;
else return b;
}
int main(){
int a=5,b=10;cout<<MAX(a,b);
float c=3.14,d=9.99;cout<<MAX(c,d);
char e='x',f='*';cout<<MAX(e,f);
}
template
执行的时候,编译器会自动根据参数的类型,把T转换为int,float等类型,进行计算。
注意,泛型的函数不会进行自动类型转换,例如cout<<MAX('a',100);
这个语句,如果使用的是泛型类型,会编译错误,但是使用普通类型不会报错,因为普通类型的函数会进行自动类型转换。
泛型类的写法:
template<typename T>
class Vector{
T *numbers;
};
(转自我之前写过的《自制vector类型》)
这样,就可以像标准库一样定义了。
在类的函数中,对于参数和部分类变量,也需要把类型指定为T,在malloc和realloc的强制转型中也是T*。
大体写法
class Stack{
private:
T *Data;
int nData;
public:
Stack(){
Data=nullptr;
nData=0;
}
bool empty(){
if(nData==0)return true;
else return false;
}
int size(){
return nData;
}
void push(T a){
nData++;
if(Data==nullptr)Data=(T*)malloc(sizeof(T));
Data=(T*)realloc(Data,nData*sizeof(T));
Data[nData-1]=a;
}
void pop(){
if(nData==0)return;
nData--;
Data=(T*)realloc(Data,nData*sizeof(T));
}
T top(){
return Data[nData-1];
}
};
构造函数的写法
将Data,nData初始化,变量的含义很简单,不再多说。
empty
判断栈的大小即可。如果大小为0,表示为空栈。
size
返回nData。
push
重头戏
void push(T a){
nData++;
if(Data==nullptr)Data=(T*)malloc(sizeof(T));
Data=(T*)realloc(Data,nData*sizeof(T));
Data[nData-1]=a;
}
首先,把栈的大小加上1。然后,如果为空指针,就使用malloc分配(原来什么都没有),否则使用realloc分配。动态分配内存,可以节约内存空间。最后,把push的数值放入栈顶。
pop
pop的操作也很简单。
void pop(){
if(nData==0)return;
nData--;
Data=(T*)realloc(Data,nData*sizeof(T));
}
pop操作需要对nData做特判,大小为零则直接退出,不然在分配时会出错。
如果nData=0,那么realloc的参数为0,相当于使用free(Data)。
top
返回栈顶元素Data[nData-1]。