棧的概念、實現以及應用
阿新 • • 發佈:2019-01-06
概念
- 棧是限定僅在表尾進行插入或刪除操作的線性表。
- 對棧來說,表尾稱為棧頂,表頭稱為棧底,不含元素的空表稱為空棧。
- 棧的修改是按照後進先出的原則進行的,也稱為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。