数据结构之堆栈的C++语言实现

[复制链接]
1348|9
 楼主| 韩山童 发表于 2017-1-5 16:17 | 显示全部楼层 |阅读模式
上次用C语言四线堆栈,本次我们使用C++来实现堆栈,利用C++的模板机制,使堆栈可以存储任意的数据类型。同时,使用链表来模拟栈,使得栈的大小可以达到硬件所能支持的最大内存空间。好了,下面马上实现。
1。首先还是先定义栈中元素的数据类型:
  1. /*堆栈使用链式存储,定义堆栈的节点数据类型*/
  2. template <typename T>
  3. struct Node
  4. {
  5.     T data;      //节点中的元素
  6.     Node* next;

  7. };


2.其次定义Stack类:
  1. /*堆栈的类定义*/
  2. template <typename T>
  3. class Stack
  4. {
  5. private:
  6.     Node<T>* mHead;      //头指针,用于管理链栈
  7.     int mSize;           //栈中元素的个数
  8. public:
  9.     Stack();
  10.     virtual ~Stack();

  11.     void push(T e);     //入栈操作
  12.     void pop(T& e);      //出栈操作
  13.     bool isEmpty();     //判断栈空
  14.     int getSize();      //返回栈中总元素

  15.     void print();    //打印栈中的元素 但不出栈
  16. };


3.下面就是实现Stack的各个函数:
(1)构造函数:
//构造函数 创建头指针
template <typename T>
Stack<T>::Stack()
{
    mHead = new Node<T>();  //创建头结点指针
    mHead->next = nullptr;      
    mSize = 0;                         //初始时栈中元素个数为0
}

(2)析构函数
/*析构函数:释放栈所占的堆内存*/
template <typename T>
Stack<T>::~Stack()
{
    Node<T>* p = mHead->next;  //p指向栈顶元素
    Node<T>* q = nullptr;           
    while (nullptr != p)  
    {
        q = p;
        p = p->next;
        delete q;  //逐一释放栈中元素
    }
    delete mHead;  //最后释放头指针
}

(3)入栈操作
//入栈:采用头插法创建
template <typename T>
void Stack<T>::push(T e)
{
    Node<T>* s = new Node<T>();
    s->data = e;
    s->next = mHead->next;
    mHead->next = s;
    ++mSize;
}

(4)出栈操作
//出栈
template <typename T>
void Stack<T>::pop(T& e)
{
    if(isEmpty())
    {
        printf("栈已空!!!\n");
        return;
    }
    Node<T>* p = mHead->next;
    mHead->next = p->next;
    e = p->data;
    delete p;
    --mSize;
}

(5)判断栈空
//判断栈空
template <typename T>
bool Stack<T>::isEmpty()
{
    return nullptr == mHead->next ? true : false;
}

(6)获取栈中元素个数
//获取栈中总元素个数
template <typename T>
int Stack<T>::getSize()
{
    return mSize;
}

(7)输出栈中元素,但不出栈
template <typename T>
void Stack<T>::print()
{
    Node<T>* p = mHead->next;
    while (nullptr != p)
    {
        cout << p->data << " ";
        p = p->next;
    }
}

4.测试
int main()
{
    Stack<int> st;
    st.push(1);
    st.push(2);
    st.push(3);
    st.push(4);
    st.push(5);
    st.push(6);

    st.print();

    cout <<endl << "栈中元素个数:" << st.getSize() << endl;
    return 0;
}

输出:
6 5 4 3 2 1
栈中元素个数:6
 楼主| 韩山童 发表于 2017-1-5 16:25 | 显示全部楼层
因为写帖子的时候太仓促,有错字的话麻烦各位大神指出来,蟹蟹!
 楼主| 韩山童 发表于 2017-1-5 17:58 | 显示全部楼层
yyy71cj 发表于 2017-1-5 16:58
倒不是错别字的问题。
你这里使用了new,这对裸编程可能存在不便。不过作为非裸编程来说,倒没什么。
堆 ...

好的
 楼主| 韩山童 发表于 2017-1-5 18:00 | 显示全部楼层

用C++实现的话 我忍不住就想用new delete,而不是C语言的malloc和free了,也喜欢用链表
dongshan 发表于 2017-1-6 12:43 | 显示全部楼层
唉,C++中有stack,不需要自己写, 是stl的一部分,属于container adaptor.
michael_llh 发表于 2017-1-6 14:57 | 显示全部楼层
自己学习的话可以选择自己实现看看,但是实际用的话可以直接考虑用STL就可以
Simon21ic 发表于 2017-1-6 15:27 | 显示全部楼层
本帖最后由 Simon21ic 于 2017-1-6 15:31 编辑
yyy71cj 发表于 2017-1-5 16:58
倒不是错别字的问题。
你这里使用了new,这对裸编程可能存在不便。不过作为非裸编程来说,倒没什么。
堆 ...

裸编还不能用链表吗?这个我倒是不知道,链表非常常用的数据结构,适合需要动态添加删减的情况下。这个是和应用需求有关的,如果裸编里有类似应用需求,那我估计也是用诸如链表的实现方法吧?
链表和数组其实一样,可以通过当前元素,访问到下一个元素。
数组中,访问以下一个元素(或者上一个元素)的方法是通过当前元素的地址加上元素长度以及填充,而且,由于数组的这个特性,所以可以用索引来访问元素。
链表里,访问下一个元素(或者上一个元素)的方式是直接通过指针。
Simon21ic 发表于 2017-1-6 22:35 | 显示全部楼层
本帖最后由 Simon21ic 于 2017-1-7 00:17 编辑
yyy71cj 发表于 2017-1-6 21:30
这倒没有特别地规定。但是,链表非常耗费空间与速度。裸编程尽量让一切都在掌握之中,而不能有太多的不定 ...

裸编程只是没有操作系统,并不代表不能有动态分配
另外,动态分配并非不确定因素,比如可以使用内存池来实现动态分配,资源使用完全可控

我原来一直以为这些只是看应用需求,和平台没什么关系
Simon21ic 发表于 2017-1-7 09:27 | 显示全部楼层
yyy71cj 发表于 2017-1-7 08:14
若是完全可控,自然可以动态分配了,这需要有足够的修为……

即使是真正的动态分配,也是可控的,比如设置一个可以动态分配的最大内存
当然,当然这种情况下,最大的风险反而是其他代码有BUG,内存溢出,覆盖了MCB
batsong 发表于 2017-1-7 14:12 | 显示全部楼层
只有允许死机的设备才能使用new和malloc,这不是我说的,这是arm编译器的手册说的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

43

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部