親自教你實(shí)現(xiàn)棧及C#中Stack源碼分析
定義
棧又名堆棧,是一種操作受限的線性表,僅能在表尾進(jìn)行插入和刪除操作。
它的特點(diǎn)是先進(jìn)后出,就好比我們往桶里面放盤子,放的時(shí)候都是從下往上一個(gè)一個(gè)放(入棧),取的時(shí)候只能從上往下一個(gè)一個(gè)?。ǔ鰲#?,這個(gè)比喻并非十分恰當(dāng),比如拿盤子的時(shí)候只是習(xí)慣從上面開始拿,也可以從中間拿,而棧的話是只能操作最上面的元素,這樣比喻只是為了便于了解。

剛開始接觸??赡軙?huì)有些疑問,我們已經(jīng)有數(shù)組和鏈表了,為什么還要棧這個(gè)操作受限制的數(shù)據(jù)結(jié)構(gòu)呢?數(shù)組和鏈表雖然靈活,但是操作起來也更容易出錯(cuò),而棧因?yàn)椴僮魇芟?,在特定場景中使用還是有優(yōu)勢的。
當(dāng)某個(gè)數(shù)據(jù)集合只涉及在一端插入和刪除數(shù)據(jù),并且滿足先進(jìn)后出的特性時(shí),我們就應(yīng)該首選“棧”這種數(shù)據(jù)結(jié)構(gòu)。
棧的實(shí)現(xiàn)
棧的實(shí)現(xiàn)方式有兩種,一種是基于數(shù)組實(shí)現(xiàn)的順序棧,另一種是基于鏈表實(shí)現(xiàn)的鏈?zhǔn)綏!K闹饕僮饕簿蛢蓚€(gè),即入棧和出棧,難度并不大😏。
先了解一下入棧(Push)和出棧(Pop),如下圖


順序棧
基于數(shù)組實(shí)現(xiàn),就面臨著數(shù)組大小固定、擴(kuò)容成本大的問題,下面是使用C#實(shí)現(xiàn)出棧和入棧簡單功能代碼。
// 基于數(shù)組實(shí)現(xiàn)的順序棧
public class ArrayStack
{
private string[] items; // 數(shù)組
private int count; // 棧中元素個(gè)數(shù)
private int n; //棧的大小
// 初始化數(shù)組,申請(qǐng)一個(gè)大小為n的數(shù)組空間
public ArrayStack(int n)
{
this.items = new string[n];
this.n = n;
this.count = 0;
}
// 入棧操作
public bool Push(string item)
{
// 數(shù)組空間不夠了,直接返回false,入棧失敗。
if (count == n) return false;
// 將item放到下標(biāo)為count的位置,并且count加一
items[count] = item;
++count;
return true;
}
// 出棧操作
public string Pop()
{
// 棧為空,則直接返回null
if (count == 0) return null;
// 返回下標(biāo)為count-1的數(shù)組元素,并且棧中元素個(gè)數(shù)count減一
string tmp = items[count - 1];
--count;
return tmp;
}
}
上面代碼有一些很明顯的缺點(diǎn),比如存儲(chǔ)的數(shù)據(jù)類型固定為string(C#中使用泛型可以很好的解決),大小固定...這只是簡單的功能演示,后面分析C#中Stack源碼時(shí)這些問題都會(huì)被化解。
出棧和入棧的時(shí)間復(fù)雜度是多少呢?這個(gè)很好計(jì)算,因?yàn)槌鰲:腿霔6贾簧婕皸m數(shù)脑兀允荗(1)。
空間復(fù)雜度呢?還是O(1),因?yàn)檫@里只額外使用了count和n兩個(gè)臨時(shí)變量。
💁♂ 空間復(fù)雜度是指除了原本的數(shù)據(jù)存儲(chǔ)空間外,算法運(yùn)行還需要額外的存儲(chǔ)空間。例子中大小為n的數(shù)組是無法省略的,也就是說這n個(gè)空間是必須的,對(duì)復(fù)雜度不了解的可以點(diǎn)擊查看一文搞定算法復(fù)雜度分析。
鏈?zhǔn)綏?/h2>
話不多說,上代碼
// 鏈表實(shí)現(xiàn)棧
public class LinkStack<T>
{
//棧頂指示器
public Node<T> Top { get; set; }
//棧中結(jié)點(diǎn)的個(gè)數(shù)
public int NCount { get; set; }
//初始化
public LinkStack()
{
Top = null;
NCount = 0;
}
//獲取棧的長度
public int GetLength()
{
return NCount;
}
//判斷棧是否為空
public bool IsEmpty()
{
if ((Top == null) && (0 == NCount))
{
return true;
}
return false;
}
//入棧
public void Push(T item)
{
Node<T> p = new Node<T>(item);
if (Top == null)
{
Top = p;
}
else
{
p.Next = Top;
Top = p;
}
NCount++;
}
//出棧
public T Pop()
{
if (IsEmpty())
{
return default(T);
}
Node<T> p = Top;
Top = Top.Next;
--NCount;
return p.Data;
}
}
//結(jié)點(diǎn)定義
public class Node<T>
{
public T Data;
public Node<T> Next;
public Node(T item)
{
Data = item;
}
}
時(shí)間復(fù)雜度和空間復(fù)雜度均為O(1).
C#中Stack源碼分析
前面我們已經(jīng)知道了順序棧和鏈?zhǔn)綏5膬?yōu)缺點(diǎn),那么C#語言中自帶的Stack是基于什么實(shí)現(xiàn)的呢?
答案是順序棧。Stack是一個(gè)泛型類,里面定義了一個(gè)泛型數(shù)組用以存儲(chǔ)數(shù)據(jù)
private T[] _array;
既然是一個(gè)順序棧,為什么在使用的過程中什么不需要初始化數(shù)組大小,也不用擔(dān)心擴(kuò)容問題呢?
當(dāng)我們實(shí)例化Stack的時(shí)候,會(huì)調(diào)用它的構(gòu)造函數(shù),初始化數(shù)組大小為0.
public Stack()
{
_array = _emptyArray;
_size = 0;
_version = 0;
}
向數(shù)組中添加元素時(shí),會(huì)檢測數(shù)組是否還有空閑容量,如果超出數(shù)組大小,將進(jìn)行擴(kuò)容
public void Push(T item)
{
if (_size == _array.Length)
{
T[] array = new T[(_array.Length == 0) ? 4 : (2 * _array.Length)];
Array.Copy(_array, 0, array, 0, _size);
_array = array;
}
_array[_size++] = item;
_version++;
}
正是因?yàn)镃#幫我們封裝好了,所以我們使用起來才感覺如此的方便。
Push()函數(shù)的時(shí)間復(fù)雜度是多少呢?當(dāng)棧中有空閑空間時(shí),可以直接添加,它的時(shí)間復(fù)雜度是O(1)。但當(dāng)內(nèi)存不夠需要擴(kuò)容時(shí),需要重新申請(qǐng)內(nèi)存,進(jìn)行數(shù)據(jù)搬移,所以時(shí)間復(fù)雜度就變成了O(n),其平均時(shí)間復(fù)雜度也為O(1).
總結(jié)

到此這篇關(guān)于手把手教你實(shí)現(xiàn)棧及C#中Stack源碼分析的文章就介紹到這了,更多相關(guān)C#中Stack源碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ftp服務(wù)器搭建部署與C#實(shí)現(xiàn)ftp文件的上傳的示例
本文主要介紹了ftp服務(wù)器搭建部署與C#實(shí)現(xiàn)ftp文件的上傳的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
解析OpenXml?Pptx的邊框虛線轉(zhuǎn)為WPF的邊框虛線問題
這篇文章主要介紹了OpenXml?Pptx的邊框虛線轉(zhuǎn)為WPF的邊框虛線,在文中用PPTX的7種直線,分別設(shè)置7種能夠設(shè)置的虛線類型,具體實(shí)例代碼跟隨小編一起看看吧2021-12-12
C#實(shí)現(xiàn)軟件監(jiān)控外部程序運(yùn)行狀態(tài)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)軟件監(jiān)控外部程序運(yùn)行狀態(tài)的方法,可實(shí)現(xiàn)監(jiān)控另一個(gè)程序的運(yùn)行狀態(tài)及觸發(fā)相應(yīng)事件的功能,是非常實(shí)用的技巧,需要的朋友可以參考下2014-12-12
C#實(shí)現(xiàn)TreeView節(jié)點(diǎn)拖拽的方法
這篇文章主要介紹了C#實(shí)現(xiàn)TreeView節(jié)點(diǎn)拖拽的方法,涉及C#針對(duì)TreeView節(jié)點(diǎn)的動(dòng)態(tài)添加及移除技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
c# 并行和多線程編程——認(rèn)識(shí)Parallel
這篇文章主要介紹了c# 并行和多線程編程的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c# Parallel的相關(guān)知識(shí),感興趣的朋友可以了解下2021-02-02
Unity ScrollView實(shí)現(xiàn)自動(dòng)吸附效果
這篇文章主要為大家詳細(xì)介紹了Unity ScrollView實(shí)現(xiàn)自動(dòng)吸附效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
c# 動(dòng)態(tài)加載dll文件,并實(shí)現(xiàn)調(diào)用其中的簡單方法
下面小編就為大家?guī)硪黄猚# 動(dòng)態(tài)加載dll文件,并實(shí)現(xiàn)調(diào)用其中的簡單方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01

