栈的概念、实现以及应用

概念

  • 栈是限定仅在表尾进行插入或删除操作的线性表。
  • 对栈来说,表尾称为栈顶,表头称为栈底,不含元素的空表称为空栈。
  • 栈的修改是按照后进先出的原则进行的,也称为LIFO

基本操作

  • InitStack(),构造一个空栈
  • ClearStack(),将栈清空
  • isEmpty(),判断栈是否为空,是返回true,否则返回false
  • StackLength(),返回栈的长度
  • Top(&elem),返回栈顶元素
  • Push(&elem),向栈顶添加元素
  • Pop(),删除栈顶元素
  • Traverse(),遍历元素一遍

实现(顺序表和链接表)

  • 顺序表
#define STACK_INIT_SIZE 5
#define INCREMENT 2

template<typename T>
class myStack
{
public:
    myStack();
    ~myStack();
    void ClearStack();
    bool isEmpty();
    int StackSize();
    T Top();
    void Push(T elem);
    T Pop();
    void StackTraverse(void (*visit)(T));
private:
    T* base;
    T* top;
    int count;
    int stackSize;
};

template<typename T>
myStack<T>::myStack()
{
    base = new T[STACK_INIT_SIZE];
    top = base;
    count = 0;
    stackSize = STACK_INIT_SIZE;
}

template<typename T>
myStack<T>::~myStack()
{
    delete[] base;
}

template<typename T>
void myStack<T>::ClearStack()
{
    delete[] base;
    base = new T[STACK_INIT_SIZE];
    top = base;
    count = 0;
}

template<typename T>
bool myStack<T>::isEmpty()
{
    if (count == 0 && top == base)
        return true;
    else
        return false;
}

template<typename T>
int myStack<T>::StackSize()
{
    return count;
}

template<typename T>
T myStack<T>::Top()
{
    return *(top-1);
}

template<typename T>
void myStack<T>::Push(T elem)
{
    //stack is full
    if (count == stackSize)
    {
        T* newBase = new T[stackSize + INCREMENT];
        //copy
        for (int i = 0; i < count; i++)
        {
            newBase[i] = base[i];
        }
        top = &(newBase[stackSize]);
        //push
        *top = elem;
        top++;
        count++;
        //delete
        delete[]base;
        base = newBase;
        stackSize += INCREMENT;
    }
    else
    {
        *top = elem;
        top++;
        count++;
    }
}

template<typename T>
T myStack<T>::Pop()
{
    count--;
    top--;
    return *top;
}

template<typename T>
void myStack<T>::StackTraverse(void(*visit)(T))
{
    for (int i = count - 1; i >= 0; i--)
    {
        visit(base[i]);
    }
}
  • 链接表,宏与上面文件共用
template<class T>
struct Node
{
    T elem;
    Node* next;
    Node()
    {
        next = NULL;
    }
};

template<class T>
class myStack2
{
public:
    myStack2();
    ~myStack2();
    void ClearStack();
    bool isEmpty();
    int StackSize();
    T Top();
    void Push(T elem);
    T Pop();
    void StackTraverse(void(*visit)(T));
private:
    Node<T>* top;
    int count;
};

template<class T>
myStack2<T>::myStack2()
{
    top = NULL;
}

template<class T>
myStack2<T>::~myStack2()
{
    Node<T>* tmp = NULL;
    while (top != NULL)
    {
        tmp = top;
        top = top->next;
        delete tmp;
    }
}

template<class T>
void myStack2<T>::ClearStack()
{
    Node<T>* tmp = NULL;
    while (top != NULL)
    {
        tmp = top;
        top = top->next;
        delete tmp;
    }
    count = 0;
}

template<class T>
bool myStack2<T>::isEmpty()
{
    return top == NULL;
}

template<class T>
int myStack2<T>::StackSize()
{
    return count;
}

template<class T>
T myStack2<T>::Top()
{
    return top->elem;
}

template<class T>
void myStack2<T>::Push(T elem)
{
    Node<T>* tmp = top;
    top = new Node<T>;
    top->elem = elem;
    top->next = tmp; 
    count++;
}

template<class T>
T myStack2<T>::Pop()
{
    T ret;
    if (top != NULL)
    {
        Node<T>* tmp = top;
        ret = tmp->elem;
        top = top->next;
        delete tmp;
        count--;
    }
    return ret;
}

template<class T>
void myStack2<T>::StackTraverse(void(*visit)(T))
{
    Node<T>* cur = top;
    while (cur != NULL)
    {
        visit(cur->elem);
        cur = cur->next;
    }
}

ps:写代码时候遇到的问题

  • 用template模板写类的时候需要把类的h文件和cpp文件写在一起,否则会报链接错误
  • 顺序表实现要难一点,因为地址是已经分好了,所以不能用判断top和NULL是否相等来判断是否空栈,所以需要top指针指向下一个push进来的,如空栈top指向分配的第一个地址,取top和pop的时候需要返回的是top-1的地址指向的元素,与链表很直观的理解不同。
  • 自己的问题:模板的格式和传递函数的写法有点生疏,算是复习了一遍。

栈的应用

  • 数制转换:将10进制数x转成n进制,只需不断让x%n的值push进栈,再让x/=x,直到x为0,然后顺序把栈中元素pop出并顺序输出即可完成进制转换。
  • 括号匹配:遇到左括号push进去,遇到右括号判断栈顶元素是否对应的左括号,是则pop出,否则括号不匹配。
  • 行编辑软件:设立一个输入缓冲区,接受用户输入的一行字符,然后逐行存入用户数据区。用户发现输入一个错误字符的时候可以用一个退格符“#”表示前一个字符无效,“@”表示之前的字符无效。栈实现:每遇到一个输入就push进去,遇到“#”就pop,遇到“@”就clear。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值