資料結構入門---棧(上)
線性表是我們學習資料結構所接觸的第一類資料結構,它是最基本,最簡單且最常用的資料結構。仔細想一下,在學習資料結構前,你應該有一門程式語言基礎。在你以往的程式設計中,‘陣列’這個東西一定沒少用吧,沒錯,陣列就是線性表的一種,最簡單最普通的線性表。以及連結串列,動態的分配記憶體是不是自由度感覺很高呢?其實想一下你在學程式語言時已經將線性表這類資料結構的基礎打好了哦
接下來我們開始介紹我們兩種常用的特殊線性表之一 — 棧
定義先擺上:限定僅在表尾進行插入和刪除操作的線性表
光看定義肯定是不能很好的理解,我們來舉個生活中常用的棧的例子:
手槍的子彈夾,我們往裡塞子彈的時候,最先塞進去的子彈被塞到了最底部,第一個射出的子彈應該是你最後塞進去的,這就是簡單的棧的例子。
從中我們看出棧的特性:後進先出 最先進棧的元素最後出棧。棧底就是彈夾底部,棧頂就是彈夾頂部射出子彈那端
現在我們理解了棧的性質,那麼我們要如何用計算機語言實現呢?
我們已經知道如何使用陣列這樣一個線性表,棧本質上就是對普通線性表加以限制,陣列可以在頭端增刪,也可在尾端增刪,那麼我們只需修改增刪的操作,把它限制成只能在一端增刪,不就成了?然後再將下標0的位置設為棧底,陣列尾部設為棧頂,我們就基本完成的棧這一資料結構的基本形態。
那麼接下來我們將棧這一資料結構用順序結構,也就是陣列實現
#include <iostream>
using namespace std;
/*棧的抽象資料型別*/
template<class T>
class Stack
{
private:
int top;
int bottom;
int MAXSIZE;
T *elements;
public:
/*構造器將棧頂與棧底置0*/
Stack()
{
this->MAXSIZE = 100;
elements = new T[MAXSIZE];
this->top = 0;
this->bottom = 0;
}
~Stack()
{
Destory();
}
/*入棧操作*/
void Push(T e)
{
if (this->IsFull())
{
cout << "棧滿" << endl;
return;
}
this->elements[top] = e;
this->top++;
}
/*出棧操作,用e返回出棧元素*/
void Pop(T &e)
{
if (this->IsEmpty())
{
cout << "空棧" << endl;
return;
}
e = this->elements[top - 1];
this->top--;
}
/*判斷是否為空棧*/
bool IsEmpty()
{
if (this->top == this->bottom)
return true;
else return false;
}
/*判斷是否棧滿*/
bool IsFull()
{
if (top == MAXSIZE)
return true;
else return false;
}
/*返回棧元素個數*/
int Length()
{
return this->top;
}
/*獲取棧頂元素*/
T GetTop()
{
return this->elements[top - 1];
}
/*將棧清空*/
void Clear()
{
this->top = this->bottom;
}
/*銷燬棧*/
void Destory()
{
delete[]elements;
this->top = this->bottom;
}
/*從底向上遍歷*/
void Traverse()
{
for (int i = this->bottom; i < this->top; i++)
{
cout << elements[i] << " ";
}
}
};
程式碼很簡單,我就一次性貼出來了。我們使用兩個指標top,bottom用來指向棧頂與棧底,最初的初始化操作將棧頂與棧頂置為下標0的位置。top始終指向棧頂元素的下一個位置,bottom指向0作為棧底
入棧過程入下圖所示:
接下來是出棧過程:
出棧過程只是下移棧頂指標,資料仍然存在但是無法訪問,接下來的入棧會將其再次覆蓋
棧空與棧滿的兩種狀態:
top==bottom==0時棧空,top==MaxSize時top指到頭了也就是棧滿
怎麼樣,是不是很簡單呢?這完全就是對陣列的基本操作。相信有程設計語言基礎的你可以輕鬆理解。
使用陣列來儲存棧是很方便的,因為限制了增刪的位置在末尾,所以不用擔心修改的時間效率。但是陣列的不可避免的弊端就是必須事先確定棧的大小,如果棧滿就需要程式設計的方式擴充大小。這時你可能想到使用連結串列,沒錯,連結串列的動態增刪是一個很好的選擇,但是在介紹鏈棧之前我要先介紹另一個提高空間利用率的手段:兩棧共享空間
假設現在需要使用兩個相同型別的棧,如果各自開闢一個數組,會出現一種情況,一個棧滿了,但另一個棧還有剩餘空閒,所以我們為什麼不想辦法利用空閒的空間呢? 因此我們可以通過某種手段,讓這兩個棧共享一個空間。
如圖,我們的思路就是將兩個棧頂指標放在陣列兩端,入棧時不斷向中間移動,我們可以很容易的知道當top1==top2時棧滿
接下來是程式碼的實現,與單棧的差別就是少了bottom指標,多了個top指標,多了個列舉型別標記選擇要操作哪個棧
#include<iostream>
using namespace std;
/*棧名標識*/
enum StackNum
{
first, second
};
template<class T>
class ShStack
{
private:
int top1;
int top2;
int MAXSIZE;
T *elements;
public:
/*初始化*/
ShStack()
{
this->top1 = 0;
this->MAXSIZE = 100;
this->top2 = this->MAXSIZE - 1;
this->elements = new T[this->MAXSIZE];
}
/*進棧*/
void Push(T e, StackNum num)
{
if (this->IsFull())
{
cout << "棧滿" << endl;
return;
}
if (num == first)
{
this->elements[this->top1] = e;
this->top1++;
}
else
{
this->elements[this->top2] = e;
this->top2--;
}
}
/*出棧*/
void Pop(T &e, StackNum num)
{
if (this->IsEmpty())
{
cout << "空棧" << endl;
return;
}
if (num == first)
{
e = this->elements[this->top1 - 1];
this->top1--;
}
else
{
e = this->elements[this->top2 + 1];
this->top2++;
}
}
/*獲取棧頂元素*/
T GetTop(StackNum num)
{
if (num == first)
return this->elements[this->top1 - 1];
else if (num == second)
return this->elements[this->top2 + 1];
}
/*獲取棧長*/
int Length(StackNum num)
{
if (num == first)
return this->top1;
else if (num == second)
return this->MAXSIZE - this->top2;
}
/*判斷是否棧滿*/
bool IsFull()
{
if (this->top1 == this->top2)
return true;
else return false;
}
/*判斷是否為空棧*/
bool IsEmpty()
{
if (this->top1 == 0 && this->top2 == this->MAXSIZE - 1)
return true;
else return false;
}
/*從底向上遍歷*/
void Traverse(StackNum num)
{
if (num == first)
{
for (int i = 0; i < this->top1; i++)
cout << this->elements[i] << " ";
}
else if (num == second)
{
for (int i = this->MAXSIZE - 1; i > this->top2; i--)
cout << this->elements[i] << " ";
}
}
/*銷燬棧*/
void Destory()
{
delete[]elements;
top1 = 0;
top2 = MAXSIZE - 1;
}
};
使用這樣的手段,需要兩個棧是相同型別,且具有空間需求相反的關係,一方增長,一方就縮短,這樣共享棧才有意義,否則兩棧同時增長,對於這種資料結構很容易快速滿棧,這樣不能很好的處理問題。因此在資料結構的設計時要根據具體情況與需求使用相應的處理策略,這樣才能更有效的利用空間
相關推薦
資料結構入門---棧(上)
線性表是我們學習資料結構所接觸的第一類資料結構,它是最基本,最簡單且最常用的資料結構。仔細想一下,在學習資料結構前,你應該有一門程式語言基礎。在你以往的程式設計中,‘陣列’這個東西一定沒少用吧,沒錯,陣列就是線性表的一種,最簡單最普通的線性表。以及連結串列,動態
資料結構------------線性表(上篇)
線性表:由n(n>=0)個數據特性相同的元素構成的有限序列 線性表中的袁旭個數n(n>=0)定義為線性表的長度,n=0時為空表 非空的線性表或線性結構特點: 1)存在唯一的一個數被稱為“第一個”的資料元素; 2)存在唯一的一個數被稱為“最後一個”的資料元素; 3)除第
資料結構與演算法(2)—— 棧(java)
1 棧的實現 1.1 簡單陣列實現棧 package mystack; public class ArrayStack { private int top; //當前棧頂元素的下標 private int[] array; public ArraySt
資料結構3--棧(java實現棧的順序儲存)
1.棧 棧也叫堆疊,是一種限制只能在某一端進行插入和刪除操作的線性表  
資料結構——順序棧(動態分配空間)的基本操作
程式碼主要來源:【資料結構】【清華大學】【嚴蔚敏】 順序棧S的基本運算如下: (1)初始化棧S (2)棧為空 (3)依次進棧元素a,b,c,d,e (4)棧為非空 (5)出棧序列:e d c b a (6)棧為空 (7)釋放棧 完整程式碼如下: #include <stdio.
資料結構與演算法(六)-揹包、棧和佇列
前言:許多基礎資料型別都和物件的集合有關。具體來說,資料型別的值就是一組物件的集合,所有操作都是關於新增、刪除或是訪問集合中的物件。而且有很多高階資料結構都是以這樣的結構為基石創造出來的,在本文中,我們將瞭解學習三種這樣的資料型別,分別是揹包(Bag)、棧(Stack)和佇列(Queue) 一、學習感悟
小白的資料結構程式碼實戰(6)----共享棧
共享棧=棧1+棧2 棧1的棧底為共享棧的首,棧2的棧底為共享棧的尾 共享棧滿:S->top1+1==S->top2 //Author:張佳琪 #include <stdio.h> #include <stdlib.h> #define
資料結構與演算法(一)——複雜度分析(上)
資料結構與演算法(一)—— 複雜度分析(上) 基礎知識就像是一座大樓的地基,只有打好基礎,才能造成萬丈高樓。資料結構與演算法是一個程式設計師的內功,只有基礎足夠紮實,才能有效提高自己的技術能力,寫出更高效、擴充套件性更好的優秀程式碼。寫這個系列記錄一下自己學習的
資料結構與演算法(三)列表結構以及棧與佇列
列表結構:要求各元素在邏輯上具有線性次序,但對其實體地址未作任何要求即動態儲存策略。 數值,前驅和後繼。List的私有頭結點和尾節點始終存在,卻對外不可見。 插入排序:字首有序,字尾無序。將字尾元素插入到字首中的合適位置。藉助於有序序列的查詢演算法。穩定演算法。O(n*n) 選擇排序:字
js資料結構和演算法(二)棧和佇列
基本概念 棧和佇列都是動態的集合,在棧中,可以去掉的元素是最近插入的哪一個。棧實現了後進先出。在佇列中,可以去掉的元素總是在集合中存在的時間最長的那一個。佇列實現了先進先出的策略。 棧的官方定義:棧(Stack)是一個後進先出(Last in first out,LIFO)
嚴蔚敏版資料結構學習筆記(3):棧
棧是隻能在表尾進行插入和刪除的一種簡單一點的線性表。表尾端是棧頂(top),表頭端是棧底(bottom),不含元素的稱為空棧。因為我們只能對棧頂的元素進行插入和刪除操作,所以棧這個資料結構就是一個很有”原則”的結構,棧的修改是按照後進先出的原則進行的,也就是LI
資料結構與演算法(十)線段樹(Segment Tree)入門
本文主要包括以下內容: 線段樹的概念 線段樹的基本操作 實現一個線段樹 LeetCode相關線段樹的問題 線段樹的概念 線段樹(Segment Tree)也是一棵樹,只不過元素的值代表一個區間。 常用區間的 統計 操作,比如一個區間的最大值(ma
資料結構 JAVA描述(三) 佇列 + 棧與佇列的比較
package Queue; /** * @description 佇列的抽象資料型別描述 * * @date 2015年12月29日 */ public interface IQueue { public void clea
野生前端的資料結構基礎練習(5)——雜湊
網上的相關教程非常多,基礎知識自行搜尋即可。 習題主要選自Orelly出版的《資料結構與演算法javascript描述》一書。 參考程式碼可見:https://github.com/dashnowords/blogs/tree/master/Structure/Hash 雜湊的基本知識
python入門知識點(上)
1.硬體系統: 主機部分:
資料結構與演算法(二)--遞迴
遞迴條件: 1.遞迴條件:每次調自己,然後記錄當時的狀態 2.基準條件:執行到什麼時候結束遞迴,不然遞迴就會無休止的呼叫自己, 遞迴的資料結構:棧(先進先出)和彈夾原理一樣,每一次呼叫自己都記錄了當時的一種狀態,然後把這種狀態的結果返回。 棧相對應的資料結構:佇列(先進後出
NodeJS簡易部落格系統(五)NodeJS入門學習(上)
一、模組 在NodeJS中,一般將程式碼合理拆分到不同的JS檔案中,每一個檔案就是一個模組,而檔案路徑就是模組名。在編寫每個模組時,都有require、exports、module三個預先定義好的變數可供使用。 1、require require函式用於在當前模組中載入和使用別的模組,傳
資料結構-----------線性表(下篇)之雙向連結串列
//----------雙向連結串列的儲存結構------------ typedef struct DuLNode { ElemType date; struct DoLNode *prior; struct DoLNode *next; } DoLNode,*DoLinkList;
資料結構---------------線性表(下篇)之單鏈表
單鏈表 特點:儲存空間不連續 結點(資料元素組成):資料域(儲存資料)和指標域(指標)A1 若用p來指向 則資料域為p->date 指標域為p->next 鏈式儲存結構: 單鏈表、迴圈連結串列、雙向連結串列根據連
野生前端的資料結構基礎練習(6)——集合
網上的相關教程非常多,基礎知識自行搜尋即可。 習題主要選自Orelly出版的《資料結構與演算法javascript描述》一書。 參考程式碼可見:https://github.com/dashnowords/blogs/tree/master/Structure/Set [TOC] 集