模拟实现 stack和queue

来源:互联网 发布:巨杉数据库好用吗 编辑:程序博客网 时间:2024/05/29 05:55

线性表是最基本、最简单、也是最常用的一种数据结构。之前我已经写了几次线性表了,分别是顺序表和链表,这两个以各种形式实现了多次,那么今天我么就再来看两种线性表,两种特殊的线性表——栈和队列

栈(stack)

首先说一下栈的概念:栈又叫后进先出的线性表(LIFO),不明白?那就再看一下它的结构吧,栈是只在一端进行插入和删除操作的,这也是它的特殊之处,这一段就是栈顶(top)。

这里写图片描述

既然栈是线性表,那么肯定有顺序栈和链式栈的区分。

顺序栈和顺序表差不多,不过,区别在于,顺序栈只在栈顶不进行插入和删除操作。如果说顺序表有头插、头删和尾插、尾删,那么顺序栈只有尾插、尾删。

链式栈也是这样,那么问题来了,我们是要将栈顶放在链式栈的头部,还是尾部,哪一个好呢?

首先来说一下,将栈顶放在头部,也就是,可以进行头插、头删,那么,也没什么;再看将栈顶放在尾部,我们要进行插入元素,那需要将尾部节点链接到新的节点,但是,尾节点在哪,还是得遍历找到尾结点,那么时间复杂度是不是就增加了。所以还是建议将栈顶放在头部,也就是说,链式栈可以进行的操作是:头插和头删

简单介绍一下栈,那么我们就来模拟实现stack吧:

#include<iostream>using namespace std;#include<assert.h>template<class T>class Stack{public:    Stack()        :_pdata(NULL)        , _size(0)        , _capacity(0)    {}    ~Stack()    {        if (NULL != _pdata)        {            delete []_pdata;            _pdata = NULL;        }        _size = 0;        _capacity = 0;    }    bool Empty()    {        return 0 == _size;    }    size_t Size()    {        return _size;    }    T& Top()    {        assert(_size>0);        return _pdata[_size - 1];    }    void CapacityIsFull()    {        if (_size == _capacity)        {            size_t new_capacity = _capacity * 2 + 3;            //new一个空间一定要记准了,不要弄错。            T* temp = new T[new_capacity];            for (size_t i = 0; i < _size; ++i)            {                temp[i] = _pdata[i];            }            delete [] _pdata;            _pdata = temp;            _capacity = new_capacity;        }    }    void Push(const T& data)    {        CapacityIsFull();        _pdata[_size] = data;        ++_size;    }    void Pop()    {        if (!Empty())        {            --_size;        }        else        {            cout << "栈已空" << endl;            return;        }    }protected:    T * _pdata;    size_t _size;    size_t _capacity;};void FunTest(){    Stack<int> s;    s.Push(1);    s.Push(2);    s.Push(3);    s.Push(4);    s.Push(5);    s.Push(6);    cout << "stack size:" << s.Size() << endl;    cout << "stack top:" << s.Top() << endl;    s.Pop();    cout << "stack size:" << s.Size() << endl;    cout << "stack top:" << s.Top() << endl;}int main(){    FunTest();    return 0;}

这里写图片描述

队列(queue)

还是先说一下它的概念:队列又称先进先出的线性表(FIFO),想想你去吃饭排的队,是不是明白许多,那么我们再来声明一下,队列的特殊之处在于:它是在一端进行删除操作,这一端称为:对头(front);在另一端进行插入操作,这一端称为:队尾(rear)。

这里写图片描述

同样,我们先来看一下顺序队列,也就是上图显示的那样,我们要进行插入元素的时候,会从尾部开始,现在,队列中有8个空间,如果插入三个元素,在删除三个元素,那么队列满了吗?

看样子是没满的,但是,你还可以在进行插入操作吗?显然是不可以的,这种现象就是“假溢出”,明明有空间,却不能进行插入元素,是不是很浪费,那么如何解决这个问题呢?

想想平时垃圾是怎么处理的,当然是回收了,我们将这个队列的头部和尾部相连,那么,在进行插入的时候,直接就会插入到原来a1的位置,然后,就可以继续进行操作了,直到队列满了。

队列满了,那么无非就是front和rear相遇了,但是如果队列中没有元素的时候,也是这个现象,这就要像个办法来区分一下了。

怎样区分队列满了,队列是空的

最简单也是最常用的方法就是定义一个计数器,这样我们就可以根据计数器显示的元素个数是不是0,来判断是不是空的,同样我们还可以根据这个来看有效元素的个数。

同样的,队列也有链式的,不过。队列的链式只能进行尾插,和头删操作。

#include<iostream>using namespace std;template<class T>struct QueueNode{    QueueNode(const T& data)    :_data(data)    , _next(NULL)    {}    T _data;    QueueNode<T> * _next;};template<class T>class Queue{public:    typedef QueueNode<T> Node;    Queue()        :_front(NULL)        , _rear(NULL)    {}    ~Queue()    {        if (_front)        {            Node* del = _front;            _front = _front->_next;            delete del;            del = NULL;        }    }    bool Empty()    {        return NULL == _front;    }    size_t Size()    {        return _size;    }    T& Front()    {        return _front->_data;    }    T& Rear()    {        return _rear->_data;    }    void Push(const T& data)//在队尾插入元素    {        if (Empty())//一定要分开讨论,不然会有访问冲突的问题        {            Node* node = new Node(data);            _front = _rear = node;            ++_size;        }        else        {            Node* node = new Node(data);            _rear->_next = node;            _rear = _rear->_next;            ++_size;        }    }    void Pop()//在对头删除元素    {        if (!Empty())        {            Node *del = _front;            _front = _front->_next;            delete del;            del = NULL;        }        else        {            cout << "队列已空" << endl;        }    }private:    Node* _front;    Node* _rear;    size_t _size;};void FunTest(){    Queue<int> q;    q.Push(1);    q.Push(2);    q.Push(3);    q.Push(4);    q.Push(5);    q.Push(6);    cout <<"the front is:"<< q.Front() << endl;    cout << "the rear is:" << q.Rear() << endl;    cout << "the size is:" << q.Size() << endl;    q.Pop();    cout << "the front is:" << q.Front() << endl;    cout << "the rear is:" << q.Rear() << endl;    cout << "the size is:" << q.Size() << endl;}int main(){    FunTest();    return 0;}

这里写图片描述

0 0
原创粉丝点击