資料結構實現基礎(三)

2021-10-10 15:49:51 字數 4070 閱讀 6457

上一講學習了一些基本的資料型別像陣列,結構。我們還學習了一些指標的基本概念。這一講,我們主要學習兩種資料型別,一種叫聯合,也叫共同體。還有一種就是鍊錶。

共同體同結構體在宣告形式和訪問方式上有些類似,但是它和結構體是完全不一樣的。

所謂共同體型別,是指將不同的資料項組成乙個整體,它們在記憶體中占用同一段儲存單元。其關鍵字為union(聯合的意思)。

定義形式為:

union 共同體名

;

由於共同體中各個成員變數在記憶體中使用同一段儲存空間,因此共同體變數的長度等於最長的成員的長度。共同體的訪問方式同結構體類似。下面是乙個共同體的例子:

union key

u;

該共同體變數占用的空間是int型別占用的空間與2位元組的最大值,即4個位元組。

#includeint main()u;	

u.k = 257;

printf("%d %d\n",u.ch[0], u.ch[1]);

return 0;

}

執行此**後,你會發現u.ch[0]和u.ch[1]的值會隨著u.k的值的改變而發生改變。由此也可以說明它們占用同一記憶體空間。在c語言中,我們已經接觸過鍊錶。鍊錶是一種重要的基礎資料結構,也是實現複雜資料結構的重要手段。它不同於陣列,其不按照線性的順序儲存資料,而是有若干個同一結構型別的「結點」依次串接而成的。且每乙個結點裡儲存著下乙個結點的位址(指標)。

優點:不需要提前知道資料的大小,而是實現靈活的記憶體動態管理。

缺點:失去了陣列方便隨機訪問的優點,且增加了結點的指標域,空間開銷較大。

頭結點:資料域為空,指標域指向首元結點(存放資料的第乙個結點)

首先是乙個表頭變數head,用來存放煉表頭結點(帶頭結點的單鏈表)的位址,鍊錶中每個結點由資料部分和下乙個結點的位址部分組成,即每個結點都包含指向下乙個結點的指標。鍊錶的最後乙個結點稱為表尾,其指標域為null(表示空位址)。

儲存特點:鍊錶中各個結點在記憶體中可能是不連續存放的,具體存放位置由系統分配。

定義:通常使用結構的巢狀來定義單向鍊錶結點的資料型別。如:

typedef struct node * ptrtonode;

struct node

;//或

strucu node

我們來看上述**的第一行:typedef struct node * ptrtonode;通過我們前面所學,我們知道這是typedef型別定義,相當於給乙個型別名起乙個別名。在這裡為什麼要給這個型別取乙個這樣的別名呢?你想過沒有?如果沒有,那就按照我的思路想想。首先這是乙個指向結構的指標型別,也就是說其儲存的是乙個結構型別的位址,而我們知道結點的指標域就是儲存下一結點的位址,所以看來此型別定義是為了方便定義結點的指標域。那麼看到ptrtonode,顧名思義表示「指向node的指標」之意。這就是為什麼要型別定義的原因,是為了更方便地明白指標域的含義。當然也可以不進行型別定義,對程式執行沒有任何影響。鍊錶是一種動態的資料結構。在進行動態儲存分配的操作中,c語言提供了幾個常用的函式:malloc(), free()。例如要申請大小為struct node結構的動態記憶體空間,可由下面語句實現:struct node * = (struct node *)malloc(sizeof(struct node));若申請成功,p指向分配記憶體空間起始位址;若未申請到記憶體空間,則p的值為null

(1)插入結點

在單向鍊錶head的某個結點p之後插入一新結點的基本過程:首先找到正確位置p,然後申請新結點t並對t的結點資訊賦值,最後將t插在p之後。

將結點t插在結點p之後:

t---->next = p---->next;//順序不能顛倒

p---->next = t;

如果需要在鍊錶的頭上插入乙個結點t,基本語句為:

t---->next = head;  //兩個語句不能顛倒

head = t;

(2)刪除結點從單向鍊錶head中刪除乙個結點的基本過程是:首先找到要刪除的結點前面的結點p

,然後刪除p之後的那個結點。基本語句為:

t = p---->next;//把待刪除的結點的位址儲存在t中

p---->next = t---->next;

free(t);

注意:刪除乙個結點後必須動態釋放該結點的空間,為此上述語句中首先要把待刪除的結點保留在t中,最後再釋放t。

t = head;

head = head---->next;

free(t);

(3)單向鍊錶的遍歷對單向鍊錶最常見的處理方式是逐個檢視鍊錶中每個結點的資料並進行處理,因此,鍊錶的遍歷是非常基礎的鍊錶程式設計方法。單向鍊錶的遍歷基本程式:

p = head;

while(p != null)

(4)鍊錶的建立在構建鍊錶時,有兩種常見的插入結點的方式:在鍊錶的頭上不斷插入新結點。在鍊錶的尾部不斷插入新結點。

如果是後者,一般需要乙個臨時的結點指標一直指向當前鍊錶的最後乙個結點,以便新結點的插入。

單向鍊錶的構成使得結點訪問要按鏈的指向進行,某一單元的後繼單元可以直接通過鏈指標(next指標)找到,而要找到其前驅單元,必須從鏈頭開始尋找。如果結點增加乙個指標域指向其前驅結點,將在犧牲空間代價的前提下,減少操作的代價。這種在單向鍊錶的基礎上,增加指向前驅單元指標(previous)的鍊錶叫做雙向鍊錶。

下圖顯示了雙向鍊錶:

單向鍊錶與雙向鍊錶的比較:

雙向鍊錶結點的資料型別與單向鍊錶相似,只是多了乙個前驅單元指標:

typedef struct dnode * ptrtodnode;

struct dnode

;

對雙向鍊錶的插入,刪除,和遍歷基本思路與單鏈表相同,但需要同時考慮前後兩個指標。定義:雙向鍊錶最後乙個單元的next指標指向鍊錶的第乙個單元,而第乙個單元的previous指標指向鍊錶的最後乙個單元,這樣構成的鍊錶稱為雙向迴圈鍊錶。

資料結構實現基礎(二)

變數是資料儲存的基本單位,而變數是有型別的。c語言事先定義了幾種基本的資料型別,供程式設計師直接使用,如整型,實型,字元型等。為了使程式設計師能夠充分表達各種複雜的資料,c語言還提供了構造複雜資料型別的手段,如陣列,結構,指標等。陣列是最基本的構造型別,它的特點是儲存多個相同型別的資料,或者說它是一...

資料結構與演算法 基礎資料結構 佇列實現

在學習佇列的實現過程中,跟著教程自己手寫了佇列的實現,理解佇列的先進先出原理。以及略微複雜的迴圈佇列形成的乙個閉環,略微吃力,還需努力,詳細說明在注釋 package com.zhouyou.queue 普通佇列的實現 public class arrayqueue public void push...

資料結構基礎知識(三)

陣列 是由同一種資料型別的資料元素組成的線性表,組成陣列的資料元素可以是初等項,也可以是組合項。一維的陣列又稱為向量,二維的陣列又稱為矩陣。陣列的抽象資料型別表示 template define defaultsize 100 enum boolean class array int getleng...