三、棧的實現
棧的定義:棧是一種特殊的線性表(容器)。
棧僅能線上性表的一端進行操作:
棧頂(top):允許操作的一端;
棧底(bottom):不允許操作的一端。
棧的特性:後進先出(Last in First Out)
棧的操作(函式):建立(stack())、銷燬(~stack())、清空(clear())、進棧(push())、出棧(pop())、獲取棧頂元素(top())、獲取棧的大小(size())。
template < typename T>
class Stack : public Object
{
public:
virtual void push( const T& e) = 0;
virtual void pop() = 0;
virtual T top() const = 0;
virtual void clear() = 0;
virtual int size() const = 0;
};
一、StaticStack順序棧設計要點:
類别範本:使用原生陣列作為棧的儲存空間
使用模板引數(<T, N>)決定棧的最大容量
程式碼實現如下:
template <typename T, int N>
class StaticStack : public Stack<T>
{
protected:
T m_space[N]; //棧儲存空間,N為模板引數
//此處已經涉及到泛指型別進行具體物件的構造了,所以效率不高。
int m_top; //棧頂標誌
int m_size; //當前棧的大小
public:
StaticStack()
{
m_top = -1;
m_size = 0;
}
int capacity() const
{
return N;
}
void push(const T& e)
{
if( m_size < N)
{
m_space[m_top + 1] = e; //為了異常安全,在複製操作符出現異常的情況下,棧內部的資料並不會出現改變
m_top++; //e可能是一個類型別,如果真的這個類型別未進行復制操作符過載,丟擲異常前不對m_top做任何改變
m_size++;
}
else
{
//丟擲異常
}
}
void pop()
{
if( m_size > 0)
{
m_top--;
m_size--;
}
else
{
//丟擲異常
}
}
T top() const { if( m_size > 0) { return m_space[m_top]; //直接返回棧頂的值 } else { //丟擲異常 } } void clear() { m_top = -1; m_size = 0; } int size() const { return m_size; } };在主函式中測試如下程式碼:
int main()
{
StaticStack<int, 5> ss;
for(int i=0; i<5; i++)
{
ss.push(i);
}
while (ss.size() > 0)
{
cout << ss.top();
ss.pop();
}
return 0;
}
輸出效果為:
小結:棧只允許線上性表的一端進行操作。
注意:StaticStack使用原生陣列作為內部儲存空間
StaticStack的最大容量由模板引數決定。
二、(LinkStack)鏈式棧的實現
問題提出:當儲存的元素為類型別時,StaticStack的物件在建立時,會多次呼叫元素型別的建構函式,影響效率。原因在於使用原生陣列作為儲存空間,在建立棧物件的時候,會呼叫泛指型別的建構函式。
鏈式棧的設計要點(本質就是連結串列):
1、類别範本,抽象父類Stack的直接子類;
2、在內部組合使用LinkList類,實現棧的鏈式儲存;
3、只在單連結串列成員物件的頭部進行操作。
實現程式碼如下:
template <typename T>
class LinkStack : public Stack <T>
{
protected:
LinkList<T> m_list;
public:
void push(const T& e) //O(1) 注:此處為頭插法
{
m_list.insert(0,e);
}
void pop() //O(1 )
{
if( m_list.length() > 0)
{
m_list.remove(0);
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No element in current stack...");
}
}
T top() const
{
if( m_list.length() > 0)
{
return m_list.get(0);
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No element in current stack...");
}
}
void clear() //O(n)
{
m_list.clear();
}
int size() const //O(1)
{
return m_list.length();
}
};
在主函式中編寫如下程式碼:
class Test : public Object
{
public:
Test()
{
cout << "Test()" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
};
int main()
{
LinkStack<Test> ls;
cout << ls.size() << endl;
return 0;
}
執行後發現,建構函式和解構函式均未執行,效率提升。棧的應用之一:符號匹配問題:
bool scan(const char* code)
{
LinkStack<char> stack;
int i=0;
bool ret = true;
code = (code == NULL)? "" : code;
while( ret && (code[i] != '\0'))
{
if( is_left(code[i]))
{
stack.push(code[i]);
}
else if(is_right(code[i]))
{
if( (stack.size()) && is_match(stack.top(), code[i]))
{
stack.pop();
}
else
{
ret = false;
}
}
else if( is_quot(code[i]))
{
if( stack.size() == 0 || !is_match(stack.top(), code[i]) ) //不匹配的時候
{
stack.push(code[i]);
}
else if(is_match(stack.top(), code[i]))
{
stack.pop();
}
}
i++;
}
return ret && (stack.size() == 0);
}
小結:鏈式棧的實現組合使用了單連結串列物件(又是不同的資料結構)。
在單連結串列的頭部進行操作能夠高效的入棧和出棧操作。
棧“後進後出”的特性適用於檢測成對出現的符號。
棧非常適合於需要“就近匹配”的場合。
相關文章
- 動態棧的實現
- Tarjan中棧的分析與SLT棧的實現
- 棧的應用和實現
- 棧的實現及基本操作
- 順序棧的實現方式
- 通過佇列實現棧OR通過棧實現佇列佇列
- 棧實現遞迴遞迴
- 關於棧實現
- 用一個棧實現另一個棧的排序排序
- java實現棧的簡單操作Java
- 演算法:最小棧的實現演算法
- 順序棧與鏈式棧的圖解與實現圖解
- 9. 題目:對佇列實現棧&用棧實現佇列佇列
- 用佇列實現棧佇列
- 用棧實現佇列佇列
- Android技術棧(三)依賴注入技術的探討與實現Android依賴注入
- 利用棧實現佇列(C語言實現)佇列C語言
- 兩個棧實現佇列佇列
- 馬踏棋盤(棧實現)
- 棧實現反序讀檔案
- 使用棧實現表示式求值,運用棧計算
- java實現單連結串列、棧、佇列三種資料結構Java佇列資料結構
- 10-C++實現棧的常見操作C++
- 原始碼閱讀之Java棧的實現原始碼Java
- 漫畫演算法:最小棧的實現演算法
- Java棧資料結構的實現方式Java資料結構
- 實現無鎖的棧與佇列(4)佇列
- 實現無鎖的棧與佇列(3)佇列
- 實現無鎖的棧與佇列(1)佇列
- 實現無鎖的棧與佇列(2)佇列
- Java面試題:棧和佇列的實現Java面試題佇列
- 用棧實現佇列,實現Enqueue和Dequeue方法佇列ENQ
- Day 10| 232.用棧實現佇列 、 225. 用佇列實現棧佇列
- 《劍指 Offer》棧實現佇列佇列
- 用JavaScript實現棧與佇列JavaScript佇列
- 兩個棧實現佇列操作佇列
- js實現資料結構--棧JS資料結構
- 用2個棧實現佇列佇列