1. 程式人生 > >棧的概念、實現以及應用

棧的概念、實現以及應用

概念

  • 棧是限定僅在表尾進行插入或刪除操作的線性表。
  • 對棧來說,表尾稱為棧頂,表頭稱為棧底,不含元素的空表稱為空棧。
  • 棧的修改是按照後進先出的原則進行的,也稱為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。