【原创】【自制系列】自制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的类型,这个类型是一个通用类型。这个语句告诉编译器,要开始泛型编程,其中T是要使用的泛型类型。
执行的时候,编译器会自动根据参数的类型,把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]。

posted @ 2021-11-27 16:41  计算机知识杂谈  阅读(296)  评论(2编辑  收藏  举报