資料結構:順序表、單鏈表、棧和佇列的簡單總結
首先,順序表、連結串列、棧和佇列都屬於線性表,都可以採用兩種基本的儲存結構:順序儲存結構和鏈式儲存結構來儲存。結構中的元素之間存在一對一的線性關係。既然,順序表、連結串列、棧和佇列都屬於線性表,那麼有必要簡單的談一談線性表。
線性結構是最常用、最簡單的一種資料結構。而線性表是一種典型的線性結構。其基本特點是線性表中的資料元素是有序且是有限的。在這種結構中:
- ① 存在一個唯一的被稱為“第一個”的資料元素;
- ② 存在一個唯一的被稱為“最後一個”的資料元素;
- ③ 除第一個元素外,每個元素均有唯一一個直接前驅;
- ④ 除最後一個元素外,每個元素均有唯一一個直接後繼。
線性表的儲存結構
線性表的儲存結構可分為順序儲存結構
順序儲存結構
用一組連續的儲存單元依次儲存線性表中的各個資料元素,使得線性表中在邏輯結構上相鄰的資料元素儲存在連續的物理儲存單元中。可以簡單的理解為順序儲存結構使用一維陣列儲存線性表中的元素。
順序儲存的線性表的特點:
◆ 線性表的邏輯順序與物理順序一致;
◆ 資料元素之間的關係是以元素在計算機內“物理位置相鄰”來體現。
鏈式儲存結構
鏈式儲存結構是一種動態儲存方式。採用一組任意的存放單元來存放線性表的元素。這組儲存單元可以是連續的也可以是不連續的。採用鏈式儲存線性表可以克服線性表:(1)插入和刪除操作需要移動大量元素(2)採用順序儲存事先必須分配還記憶體單元,即定義線性表的長度,而事先分配好的大小不一定可以剛好滿足需求(當然這一缺點可以通過擴容來克服,但相對比較麻煩)的缺點。
Ⅰ )順序表
順序表是採用順序儲存結構的線性表,順序表可理解為採用一維陣列儲存的線性結構(陣列也是一種資料結構)順序表的儲存結果如下圖所示:
假設線性表中有n個元素,每個元素佔k個儲存單元,第一個元素的地址為Loc(a1),則第i個元素的地址Loc(ai):
Loc(ai) = Loc(a1) + (i-1) * k;
其中Loc(a1)稱為基地址。
用陣列來儲存線性表的元素之外,順序表還應該用一個變數來表示線性表的長度屬性,利用C語言的結構型別來定義順序表型別。
#define ListSize 100 //線性表的最大長度
typedef int DataType;
typedef struct
{
DataType data[ListSize]; //用陣列儲存線性表中的元素
DataType length; //順序表中元素的個數
}SeqList, *PSeqList;
DataType是資料元素型別,可以根據需要定義,可以使用SeqList定義資料表型別變數,使用*PSeqList定義資料表指標變數;
順序表、單鏈表、棧和佇列的基本操作前邊的文章中已經講過,這裡就不贅述了,在後面的文章中給出了相關連線,可供參考:
Ⅱ)單鏈表
單連結串列是採用鏈式儲存結構的線性表。資料元素儲存在非連續的記憶體單元中,通過指標將各個記憶體單元連結在一起,最有一個節點的指標指向 NULL 。單鏈表不需要提前分配固定大小儲存空間,當需要儲存資料的時候分配一塊記憶體並將這塊記憶體插入連結串列中。
單鏈表是由一系列結點組成的,通過指標域把結點按照線性表中的邏輯元素連線在一起。為了能正確表示結點間的邏輯關係,在儲存每個結點值的同時,還必須儲存指示其後繼結點的地址(或位置)資訊,這個資訊稱為指標(pointer)或鏈(link)。這兩部分組成了連結串列中的結點結構,單鏈表的結點結結構如下圖:
使用箭頭表示連結串列中的指標,單鏈表的可以表示成用箭頭連線起來的結點序列,如下圖所示:
圖示為帶頭結點的單鏈表,實際上單鏈表是沒有頭結點的,頭結點只是為了操作方便,在單鏈表的第一個結點前附設的一個結點使用頭指標指向頭結點。不帶頭結點的單鏈表,頭指標指向第一個結點,判空條件為pHead == NULL;
//使用C語言的結構型別來定義單鏈表表型別。
typedef int DataType; //資料型別
typedef struct Node
{
DataType Data; //資料元素
struct Node* Next; //指向結點直接後繼的指標
}Node, *LinkList;
Ⅲ)棧
棧是一種先進後出的線性結構。只允許在棧的一端進行插入和刪除操作,稱為棧頂,棧的另一端稱為棧底。棧頂的當前位置是動態變化的,由棧頂指標的位置指示,棧底指向棧的末尾。順序棧使用順序表實現,亦或者說是採用陣列實現。順序棧的示意圖如下:
圖示top==0 表示棧空的順序棧,每次,入棧時先使元素入棧,然後棧頂指標+1,出棧時,先將棧頂指標top--,然後元素出棧。還可以用top==-1表示棧空,入棧時先使棧頂指標top++,然後元素入棧;出棧時先將棧頂指標top--,然後元素出棧。順序棧的基本操作,點選開啟連結
//使用C語言的結構型別來定義順序棧型別。
#define MAXSIZE 100 //棧的最大元素個數
typedef int DataType;
typedef struct
{
DataType stack[MAXSIZE];
int top; //棧頂指標
}SeqStack;
棧還可以採用鏈式儲存結構來儲存,稱為鏈式棧。鏈式棧使用單鏈表來實現,與順序棧相比,鏈棧的結點空間是動態申請的因此一般不存在棧滿上溢現象。鏈式棧的基本操作,點選開啟連結
Ⅳ)佇列
佇列是一種先進先出的線性結構,只允許在表的一端進行插入和刪除操作,當然:雙端佇列除外,允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。
//使用C語言的結構型別來定義順序佇列型別。
#define MaxSize 100 //佇列的最大容量
typedef int DataType; //佇列中元素型別
typedef struct Queue
{
DataType Queue[MaxSize];
int fornt; //隊頭指標
int rear; //隊尾指標
}SeqQueue;
由於在入隊和出隊的過程中隊頭指標和隊尾指標只增加不減小,致使被刪除元素的空間無法被重新利用,因此,可能會存在這樣一種情況:儘管,佇列中實際元素個數遠遠小於陣列大小(佇列長度)但可能尾指標已超出陣列空間的上界,而不能進行入隊操作,這種現象,稱之為“假溢位”。
為了充分利用儲存空間,消除這種”假溢位”,可以採用的方法是:將為佇列分配的空間看成為一個首尾相接的圓環,並稱這種佇列為迴圈佇列。 在迴圈佇列中當隊尾指標rear 達到最大值Maxsize - 1 時,其隊尾指標加1操作,使其指向隊頭指標,這一過程可以使用數學中的取餘運算來實現。
//使用C語言的結構型別來定義順序迴圈佇列型別。
#define MaxSize 100 //佇列的最大容量
typedef int DataType;
typedef struct SeqQueue
{
DataType Queue[MaxSize]; //使用陣列來儲存佇列中的元素
int fornt;
int rear;
}SeqCirQueue;
迴圈佇列在隊空和隊滿時,都是隊頭指標和隊尾指標指向同一個位置,即:front==rear
為了區分這兩種情況,可以少用一個儲存空間,隊空的判斷條件不變,以隊尾指標rear加1等於隊頭指標為佇列的判滿條件。即:
- ◆ rear所指的單元始終為空。
- ◆ 迴圈佇列為空:front=rear 。
- ◆ 迴圈佇列滿:(rear+1)%maxsize =front。
還可以使用標誌量的方法來克服佇列的“假溢位”現象。即:增加一個標誌位設標誌位tag,初始化時將tag置為0,當入隊成功時tag = 1;出隊成功時tag = 0;佇列為空的判斷條件為:(SCQ->front == SCQ->rear) && (SCQ->tag == 0)
佇列為滿的判斷條件為:(SCQ->front == SCQ->rear) && (SCQ->tag == 1)
。使用標誌量的方法可以將佇列中的所有空間都用於存放佇列中的元素,使用標誌量克服順序佇列的假溢位現象。
同棧一樣,佇列也可以採用鏈式儲存結構來儲存。採用鏈式儲存結構儲存的佇列稱為鏈式佇列,使用單鏈表來實現。
//使用C語言的結構型別來定義鏈式佇列型別。
typedef int DataType; //資料型別
typedef struct Node //連結串列的結點結構
{
DataType _data;
struct Node* _next;
}LinkQueueNode;
typedef struct
{
LinkQueueNode* front; //隊頭指標
LinkQueueNode* rear; //隊尾指標
}LinkQueue;
佇列的實現:順序佇列、迴圈佇列、鏈式佇列上邊的參考程式碼中,鏈式佇列使用帶頭結點的單鏈表實現,不帶頭結點的鏈式佇列參考:點選開啟連結