1. 程式人生 > >資料結構圖文解析之:棧的簡介及C++模板實現

資料結構圖文解析之:棧的簡介及C++模板實現

0. 資料結構圖文解析系列

1. 棧的簡介

1.1棧的特點

棧(Stack)是一種線性儲存結構,它具有如下特點:

  1. 棧中的資料元素遵守”先進後出"(First In Last Out)的原則,簡稱FILO結構。
  2. 限定只能在棧頂進行插入和刪除操作。

1.2棧的相關概念

棧的相關概念:

  1. 棧頂與棧底:允許元素插入與刪除的一端稱為棧頂,另一端稱為棧底。
  2. 壓棧:棧的插入操作,叫做進棧,也稱壓棧、入棧。
  3. 彈棧:棧的刪除操作,也叫做出棧。

例如我們有一個儲存整型元素的棧,我們依次壓棧:{1,2,3}

在壓棧的過程中,棧頂的位置一直在”向上“移動,而棧底是固定不變的。
如果我們要把棧中的元素彈出來:

出棧的順序為3、2、1 ,順序與入棧時相反,這就是所謂的”先入後出“。
在彈棧的過程中,棧頂位置一直在”向下“移動,而棧底一直保持不變。

如果你玩過一種稱為漢諾塔的益智玩具,你就會知道遊戲中小圓盤的存取就是一種先進後出的順序,一個圓柱就是一個棧:

1.3 棧的操作

棧的常用操作為:

  1. 彈棧,通常命名為pop
  2. 壓棧,通常命名為push
  3. 求棧的大小
  4. 判斷棧是否為空
  5. 獲取棧頂元素的值

1.4 棧的儲存結構

棧既然是一種線性結構,就能夠以陣列或連結串列(單向連結串列、雙向連結串列或迴圈連結串列)作為底層資料結構。
本文我們以陣列、單向連結串列為底層資料結構構建棧。

2. 基於陣列的棧實現

當以陣列為底層資料結構時,通常以陣列頭為棧底,陣列頭到陣列尾為棧頂的生長方向:

2.1 棧的抽象資料型別

棧提供瞭如上所述操作的相應介面。

template<typename T>
class ArrayStack
{
public:
    ArrayStack(int s = 10);    //預設的棧容量為10
    ~ArrayStack();
 
public:
    T top();            //獲取棧頂元素
    void push(T t);        //壓棧操作
    T pop();            //彈棧操作
    bool isEmpty();        //判空操作
    int size();            //求棧的大小
 
private:
    int count;            //棧的元素數量
    int capacity;        //棧的容量
    T * array;            //底層為陣列
};
  1. count 為棧的元素數量,capacity為棧的容量,count<=capacity,當棧滿的時候,count = capacity。
  2. 本實現中不支援棧的動態擴容,棧滿的時候無法再插入元素。棧的容量在定義棧的時候就需要指定,預設的棧容量為10。

2.2 棧的具體實現

棧的實現還是相對簡單的,很容易理解。這裡就不再畫蛇添足了。

 /*棧的判空操作*/
template <typename T>
bool ArrayStack<T>::isEmpty()
{
     return count == 0; //棧元素為0時為棧空
};
 
/*返回棧的大小*/
 template <typename  T>
int ArrayStack<T>::size()
{
     return count;
};
 
/*插入元素*/
template <typename T>
void ArrayStack<T>::push(T t)
{
     if (count != capacity)    //先判斷是否棧滿
     {
         array[count++] = t;   
     }
};
 
/*彈棧*/
template <typename T>
T ArrayStack<T>::pop()
{
     if (count != 0)    //先判斷是否是空棧
     {
         return array[--count];
     }
};
 
/*獲取棧頂元素*/
template <typename T>
T ArrayStack<T>::top()
{
     if (count != 0)
     {
         return array[count - 1];
     }
};
 

2.3 棧的程式碼測試

int _tmain(int argc, _TCHAR* argv[])
{
    ArrayStack <int> p(5);
    for (int i = 0; i < 5; i++)
    {
        p.push(i);
    }
    cout << "棧的大小:"<<p.size() << endl;
    cout << "棧是否為空:"<<p.isEmpty() << endl;
    cout << "棧頂元素:"<<p.top() << endl;
    cout << "依次出棧:" << endl;
    while (!p.isEmpty())
    {
        cout << p.pop() << endl;
    }
    getchar();
    return 0;
}

測試結果:

棧的大小:5
棧是否為空:0
棧頂元素:4
依次出棧:
4
3
2
1
0

3. 基於單鏈表的棧

以連結串列為底層的資料結構時,以連結串列頭為作為棧頂較為合適,這樣方便節點的插入與刪除。壓棧產生的新節點將一直出現在連結串列的頭部;

3.1 連結串列節點

/*連結串列節點結構*/
template <typename T>
struct Node
{
    Node(T t) :value(t), next(nullptr){};
    Node() :next(nullptr){};
 
public:
    T value;
    Node<T>* next;
};
  1. value:棧中元素的值
  2. next:連結串列節點指標,指向直接後繼

3.2 棧的抽象資料型別

基於連結串列的棧提供的介面與基於陣列的棧一致。

 
/*棧的抽象資料結構*/
template <typename T>
class LinkStack
{
public:
     LinkStack();
     ~LinkStack();
public:
 
     bool isEmpty();
     int size();
     void push(T t);
     T pop();
     T top();
 
private:
 
     Node<T>* phead;
     int count;
};

3.3 棧的具體實現

/*返回棧的大小*/
template <typename T>
int LinkStack<T>::size()
{
     return count;
};
/*棧的判空操作*/
template <typename T>
bool LinkStack<T>::isEmpty()
{
     return count == 0;
};
/*插入元素*/
template<typename T>
void LinkStack<T>::push(T t)
{
     Node <T> *pnode = new  Node<T>(t);
     pnode->next = phead->next;
     phead->next = pnode;
     count++;
};
/*彈棧*/
template <typename T>
T LinkStack<T>::pop()
{
     if (phead->next != nullptr) //棧空判斷
     {
         Node<T>* pdel = phead->next;
         phead->next = phead->next->next;
         T value = pdel->value;
         delete pdel;
         count--;
         return value;
     }
};
/*獲取棧頂元素*/
template <typename T>
T LinkStack<T>::top()
{
    if (phead->next!=nullptr)
        return phead->next->value;
};

3.4 棧的程式碼測試

int _tmain(int argc, _TCHAR* argv[])
{
    LinkStack <string> lstack;
    lstack.push("hello");
    lstack.push("to");
    lstack.push("you!");
 
    cout << "棧的大小:" << lstack.size() << endl;
    cout <<"棧頂元素:"<< lstack.top() << endl;
 
    while (!lstack.isEmpty())
    {
        lstack.pop();
    }
 
    cout << "棧的大小:" << lstack.size() << endl;
 
    getchar();
    return 0;
}

測試結果:

棧的大小:3
棧頂元素:you!
棧的大小:0

4. 棧的完整程式碼

相關推薦

資料結構圖文解析簡介C++模板實現

0. 資料結構圖文解析系列 1. 棧的簡介 1.1棧的特點 棧(Stack)是一種線性儲存結構,它具有如下特點: 棧中的資料元素遵守”先進後出"(First In Last Out)的原則,簡稱FILO結構。 限定只能在棧頂進行插入和刪除操作。 1.2棧的相關概念 棧的相關概念: 棧頂與棧底:允許元素

資料結構圖文解析二分查詢與其相關的幾個問題解析

0. 資料結構圖文解析系列 1. 二分查詢簡介 二分查詢大家都不陌生,可以說除了最簡單的順序查詢之外,我們第二個接觸的查詢演算法就是二分查找了。順序查詢的時間複雜度是O(n),二分查詢的時間複雜度為O(logn)。在面試中二分查詢被考察的概率還是比較高的,上次去面試時就遇到手寫二分查詢的題目。二分查詢不難,

資料結構圖文解析樹的簡介二叉排序樹C++模板實現.

  閱讀目錄 0. 資料結構圖文解析系列 1. 樹的簡介 1.1 樹的特徵 1.2 樹的相關概念 2. 二叉樹簡介 2.1 二叉樹的定義 2.2 斜樹、滿二叉樹、完全二叉樹、二叉查詢樹 2

資料結構圖文解析佇列詳解與C++模板實現

正文 回到頂部 0. 資料結構圖文解析系列 回到頂部 1. 佇列簡介 回到頂部 1.1 佇列的特點 佇列(Queue)與棧一樣,是一種線性儲存結構,它具有如下特點: 佇列中的資料元素遵循“先進先出”(First In First Out)的原則,簡稱FI

資料結構圖文解析二叉堆詳解C++模板實現

0. 資料結構圖文解析系列 1. 二叉堆的定義 二叉堆是一種特殊的堆,二叉堆是完全二叉樹或近似完全二叉樹。二叉堆滿足堆特性:父節點的鍵值總是保持固定的序關係於任何一個子節點的鍵值,且每個節點的左子樹和右子樹都是一個二叉堆。 當父節點的鍵值總是大於或等於任何一個子節點的鍵值時為最大堆。 當父節點的鍵值總是小於

資料結構圖文解析陣列、單鏈表、雙鏈表介紹C++模板實現

0. 資料結構圖文解析系列 1. 線性表簡介 線性表是一種線性結構,它是由零個或多個數據元素構成的有限序列。線性表的特徵是在一個序列中,除了頭尾元素,每個元素都有且只有一個直接前驅,有且只有一個直接後繼,而序列頭元素沒有直接前驅,序列尾元素沒有直接後繼。 資料結構中常見的線性結構有陣列、單鏈表、雙鏈表、迴圈

資料結構圖文解析哈夫曼樹與哈夫曼編碼詳解C++模板實現

0. 資料結構圖文解析系列 1. 哈夫曼編碼簡介 哈夫曼編碼(Huffman Coding)是一種編碼方式,也稱為“赫夫曼編碼”,是David A. Huffman1952年發明的一種構建極小多餘編碼的方法。 在計算機資料處理中,霍夫曼編碼使用變長編碼表對源符號進行編碼,出現頻率較高的源符號採用較短的編碼,

資料結構圖文解析直接插入排序及其優化(二分插入排序)解析C++實現

0. 資料結構圖文解析系列 1. 插入排序簡介 插入排序是一種簡單直觀的排序演算法,它也是基於比較的排序演算法。它的工作原理是通過不斷擴張有序序列的範圍,對於未排序的資料,在已排序中從後向前掃描,找到相應的位置並插入。插入排序在實現上通常採用就地排序,因而空間複雜度為O(1)。在從後向前掃描的過程中,需要反

再談資料結構(一)和佇列

1 - 前言 棧和佇列是兩種非常常用的兩種資料結構,它們的邏輯結構是線性的,儲存結構有順序儲存和鏈式儲存。在平時的學習中,感覺雖然棧和佇列的概念十分容易理解,但是對於這兩種資料結構的靈活運用及程式碼實現還是比較生疏。需要結合實際問題來熟練佇列和棧的操作。 2 - 例題分析 2.1

資料結構AVL樹詳解C++模板實現

AVL樹簡介AVL樹的名字來源於它的發明作者G.M. Adelson-Velsky 和 E.M. Landis。AVL樹是最先發明的自平衡二叉查詢樹(Self-Balancing Binary Search Tree,簡稱平衡二叉樹)。一棵AVL樹有如下必要條件:條件一:它必

資料結構》實驗三和佇列實驗報告

一..實驗目的      鞏固棧和佇列資料結構,學會運用棧和佇列。 1.回顧棧和佇列的邏輯結構和受限操作特點,棧和佇列的物理儲存結構和常見操作。 2.學習運用棧和佇列的知識來解決實際問題。 3.進一步鞏固程式除錯方法。 4.進一步鞏固模板程式設計。 二.實驗時間    準備

資料結構與演算法

視訊課堂https://edu.csdn.net/course/play/7621 目標 在本章中 , 你將學到 : 識別棧的特性 實施棧

資料結構java版和佇列》

1、棧。(Android的Activity載入是基礎棧結構的)底層使用陣列實現package ch4; /** * 棧 * @author Howard * 特點: * 1、通常情況作為程式設計

資料結構》實驗三和佇列實驗 (實驗報告)

一.實驗目的      鞏固棧和佇列資料結構,學會運用棧和佇列。 1.回顧棧和佇列的邏輯結構和受限操作特點,棧和佇列的物理儲存結構和常見操作。 2.學習運用棧和佇列的知識來解決實際問題。 3.進一步鞏固程式除錯方法。 4.進一步鞏固模板程式設計。 二.實驗內

java入門---資料結構操作例項的方法實現字串反轉

    以下例項演示了使用使用者自定義的方法 StringReverserThroughStack() 來實現字串反轉:import java.io.IOException; public class

資料結構》實驗三和佇列實驗

《資料結構》實驗三:    棧和佇列實驗 一..實驗目的      鞏固棧和佇列資料結構,學會運用棧和佇列。 1.回顧棧和佇列的邏輯結構和受限操作特點,棧和佇列的物理儲存結構和常見操作。 2.學習運用棧和佇列的知識來解決實際問題。 3.進一步鞏固程式除錯方法。 4.進一步鞏

資料結構》實驗三 和佇列實驗

 一..實驗目的      鞏固棧和佇列資料結構,學會運用棧和佇列。 1.回顧棧和佇列的邏輯結構和受限操作特點,棧和佇列的物理儲存結構和常見操作。 2.學習運用棧和佇列的知識來解決實際問題。 3.進一步鞏固程式除錯方法。 4.進一步鞏固模板程式設計。 三..實驗內容

Java資料結構與演算法stack

目錄:1.棧概述2.陣列實現自定義棧3.連結串列實現自定義棧4.集合實現自定義棧 1.棧概述棧和佇列一樣,也是線性表的一種,它唯一的特點是需要滿足先進後出(FILO)的規則,也就是隻能對棧的一頭進行操作,新增資料 稱為壓棧,移除資料稱為彈棧。而在java中棧的實現可以通過陣

JavaScript 資料結構與演算法美 - 記憶體與堆記憶體 、淺拷貝與深拷貝

前言 想寫好前端,先練好內功。 棧記憶體與堆記憶體 、淺拷貝與深拷貝,可以說是前端程式設計師的內功,要知其然,知其所以然。 筆者寫的 JavaScript 資料結構與演算法之美 系列用的語言是 JavaScript ,旨在入門資料結構與演算法和方便以後複習。 棧 定義 後進者先出,先進者後出,簡

一本正經的聊資料結構(3)和佇列

![](https://cdn.geekdigging.com/DataStructure/head.png) 前文傳送門: [「一本正經的聊資料結構(1):時間複雜度」](https://www.geekdigging.com/2020/03/28/6072951828/) [「一本正經的聊資料結構(