1.之前的一篇文章里面写的是使用vector或者原始数组来实现一个栈,这篇文章则是使用链表来实现一个栈。
2.使用链表来实现栈的好处在于:
i.push 和pop 操作 都是与链表长度无关的。
ii.所需的空间总是跟所要处理的数据的大小成正比。
3.实现:
list.hpp
#ifndef LIST_HPP
#define LIST_HPP
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class MyList
{
public:
MyList(); //构造函数,只用把头指针置为空就行
~MyList();
void insert(T item); //向链表里面插入数据,在表头实现插入
T deleteFirst(); //删除第一个节点
bool isEmpty();
unsigned int size();
private:
class Node { //内部类,节点类。
public:
Node(T item) : data(item), next(NULL){}
~Node(){}
T data; //数据
Node* next; //链接
};
Node* head; //链表的头指针
};
template <typename T>
MyList<T>::MyList() : head(NULL)
{
}
template <typename T>
MyList<T>::~MyList(){}
template <typename T>
void MyList<T>::insert(T item)
{
if (isEmpty()) //如果链表为空,新建一个节点,并让头指针指向这个节点。
{
Node* current = new Node(item);
head = current;
}
else //如果链表不为空,新建一个节点,并让next的值为当前的头指针的值,并把head重新赋值
{
Node* newNode = new Node(item);
newNode->next = head;
head = newNode;
}
}
template <typename T>
T MyList<T>::deleteFirst()
{
if(isEmpty()) //如果链表为空,那么输出提示信息,返回0;
{
cout << "The data is empty" << endl;
}
else
{
Node* deleteNode = head;
T data = deleteNode->data;
head = head->next; //修改head的指向
delete deleteNode; //释放内存
return data;
}
return 0;
}
//模版特化,针对string类型,模版这一块掌握不是很好,可以考虑去模版或者全特化
template <>
string MyList<string>::deleteFirst()
{
string data("");
if(isEmpty())
{
cout << "The data is empty" << endl;
}
else
{
Node* deleteNode = head;
data = deleteNode->data;
head = head->next;
delete deleteNode;
}
return data;
}
//判空函数
template <typename T>
bool MyList<T>::isEmpty()
{
return head == NULL;
}
template <typename T>
unsigned int MyList<T>::size()
{
unsigned int size = 0;
while(head != NULL)
{
size++;
head = head->next;
}
return size;
}
#endif
stack.hpp
#ifndef STACK_HPP
#define STACK_HPP
#include "list.hpp"
template <typename T>
class MyStack
{
public:
MyStack();
~MyStack();
T pop();
void push(T item);
bool isEmpty();
private:
MyList<T> dataList;
};
template <typename T>
MyStack<T>::MyStack() : dataList(){}
template <typename T>
MyStack<T>::~MyStack(){}
template <typename T>
T MyStack<T>::pop()
{
return dataList.deleteFirst(); //pop操作直接调用list 的删除头节点的函数
}
template <typename T>
void MyStack<T>::push(T item)
{
dataList.insert(item); //push操作直接调用list的在表头添加节点的函数
}
template <typename T>
bool MyStack<T>::isEmpty()
{
return dataList.isEmpty();
}
#endif
main.cpp
#include "stack.hpp"
int main(int argc, char** argv)
{
MyStack<string> myStack;
for (int i = 0; i != 10; ++i)
{
myStack.push(std::to_string(i) + 'a');
}
while (!myStack.isEmpty())
{
cout << myStack.pop() << " ";
}
cout << endl;
return 0;
}
4.总结:
(1)我们使用链表来代替数组当做栈的内部数据结构的好处有很多:省去了数组的新申请内存和移动数据的操作,使得push和pop的操作所需的时间跟已经在栈里面的元素的多少没有关系,仅使用单链表即可完成栈的构造,因为我们的链表只用在表头进行操作,而不会设计到其它地方的修改。
(2)在使用了模版之后,我们可以处理更多的类型,这就极大地提升了我们的效率。