1. 程式人生 > >靜態連結串列及C語言實現

靜態連結串列及C語言實現

邏輯結構上相鄰的資料元素,儲存在指定的一塊記憶體空間中,資料元素只允許在這塊記憶體空間中隨機存放,這樣的儲存結構生成的連結串列稱為靜態連結串列
靜態連結串列和動態連結串列的區別:靜態連結串列限制了資料元素存放的位置範圍;動態連結串列是整個記憶體空間。 圖1 靜態連結串列的儲存結構

靜態連結串列的構建方法

靜態連結串列使用陣列這一資料型別預先申請足夠大的記憶體空間。

由於各資料元素在陣列申請的記憶體空間內隨機存放,為了體現邏輯上的相鄰,為每一個數據元素配備一個具有指標作用的整形變數,用於記錄下一元素在陣列中的位置。

在陣列申請的儲存空間中,各資料元素雖隨機儲存,每一個元素都記錄著下一元素在陣列中的位置,通過前一個元素,可以找到下一個元素,構成了一條連結串列,這條被侷限在特定記憶體空間的連結串列就是靜態連結串列。

靜態連結串列中結點的構成

靜態連結串列中每個結點既有自己的資料部分,還需要儲存下一個結點的位置,所以靜態連結串列的儲存實現使用的是結構體陣列,包含兩部分: 資料域 和 遊標(存放的是下一個結點在陣列中的位置下標)。

實現程式碼:
  1. typedef struct {
  2. int data;//資料域
  3. int cur;//遊標
  4. }component;
例如:使用靜態連結串列儲存(1,2,3,4,5),建立陣列a[7]: 圖2 靜態連結串列

圖2 中,連結串列頭指標指向 a[0] ,表示為第一個結點,資料域存放的是 1,通過遊標確定,下一個結點的位置在 a[3] ,資料域存放的是 2 ,依次類推。若遊標為 0,表示此結點為連結串列的最後一個結點。

靜態連結串列的空間重複利用

由於靜態連結串列提前申請了有限的記憶體空間,在使用的過程中,極有可能會出現申請的記憶體空間不足,需要使用之前被遺棄的記憶體空間。 被遺棄的意思是:之前已經使用,但是後期對該結點做了摘除操作,該記憶體空間中存放的是已經不用的垃圾資料。 所以,在整個過程中,需要自己動手把兩者區分開,也就是需要自己實現 malloc 和 free 兩個函式的作用。

解決的辦法是:提前將所有未被使用的結點鏈成一個備用連結串列。需要對連結串列做插入操作時,從備用連結串列上摘下一個結點使用;刪除連結串列中的結點時,刪除的同時連結到備用連結串列上,以備下次使用。


圖3 備用連結串列和資料鏈表 圖3 分析:

第一步:備用連結串列:(0,1)(1,2)(2,3)(3,4)(4,5)(5,6)(6,0)
              資料鏈表中還沒有資料

第二步:向資料鏈表中插入一個數據,將備用連結串列上的(1,2)摘下下,提供給資料元素使用,備用連結串列的(0,1)遊標直接變成2就可以了:
              備用連結串列:(0,2)(2,3)(3,4)(4,5)(5,6)(6,0)
              資料鏈表:(1,0)

第三步:繼續向資料鏈表中插入一個數據,備用連結串列把(2,3)摘下來,備用連結串列中的(0,1)直接變成3就可以了:
              備用連結串列:(0,3)(3,4)(4,5)(5,6)(6,0)
              資料鏈表:(1,2)(2,0)

以此類推。以上為插入結點的過程,在刪除結點的反方向操作過程中,只需要將被刪除結點從資料鏈表上摘除,並新增到備用連結串列中即可(也就是隻改變相關結點的遊標的值)。

建立並初始化連結串列

建立靜態連結串列 S,儲存線性表(a,b,c,d):
  1. 建立結構體陣列,例如名為 array,儲存空間足夠大;
  2. 先將 array 陣列中的分量全部連結到備用連結串列上;(使用 reserveArr 函式實現)
  3. 從備用連結串列上申請一個分量作為連結串列 S 的頭結點,每次從備用連結串列上申請分量連結到 S 連結串列中,依次類推;( mallocArr 函式用於每次向備用連結串列申請一個結點的空間,initArr 函式用於初始化靜態連結串列)
  4. 當儲存到最後一個結點時,遊標設定為 0。

程式碼實現:
  1. //建立備用連結串列
  2. void reserveArr(component*array){
  3. for (int i=0; i<maxSize; i++) {
  4. array[i].cur=i+1;//將每個陣列分量連結到一起
  5. }
  6. array[maxSize-1].cur=0;//連結串列最後一個結點的遊標值為0
  7. }
  8. //提取分配空間
  9. int mallocArr(component * array){
  10. //若備用連結串列非空,則返回分配的結點下標,否則返回0(當分配最後一個結點時,該結點的遊標值為0)
  11. int i=array[0].cur;
  12. if (array[0].cur) {
  13. array[0].cur=array[i].cur;
  14. }
  15. return i;
  16. }
  17. //初始化靜態連結串列
  18. int initArr(component*array){
  19. reserveArr(array);//連結備用連結串列
  20. //從備用連結串列中拿出一個分量作為連結串列的頭結點,返回的是這個分量的下標
  21. int body=mallocArr(array);
  22. //宣告一個變數,把它當指標使,指向連結串列的最後的一個結點,因為連結串列為空,所以和頭結點重合
  23. int tempBody=body;
  24. for (int i=1; i<5; i++) {
  25. int j=mallocArr(array);//從備用連結串列中拿出空閒的分量
  26. array[tempBody].cur=j;//將申請的空線分量連結在連結串列的最後一個結點後面
  27. array[j].data='a'+i-1;//給新申請的分量的資料域初始化
  28. tempBody=j;//將指向連結串列最後一個結點的指標後移
  29. }
  30. array[tempBody].cur=0;//新的連結串列最後一個結點的指標設定為0
  31. return body;
  32. }
程式最終效果圖:

注:array[0]用作備用連結串列的頭結點,array[1]用作存放資料的連結串列的頭結點,所以array[0]和array[6]為備用連結串列上的結點

靜態連結串列中查詢資料

一般情況下,訪問靜態連結串列只能通過頭結點(頭結點在陣列中的位置下標是知道的),所以查詢資料通過遍歷連結串列的方式實現。

實現程式碼:
  1. //在以body作為頭結點的連結串列中查詢資料域為elem的結點在陣列中的位置
  2. int selectElem(component * array,int body,char elem){
  3. int tempBody=body;
  4. //當遊標值為0時,表示連結串列結束
  5. while (array[tempBody].cur!=0) {
  6. if (array[tempBody].data==elem) {
  7. return tempBody;
  8. }
  9. tempBody=array[tempBody].cur;
  10. }
  11. return -1;//返回-1,表示在連結串列中沒有找到該元素
  12. }

靜態連結串列中更改資料

更改連結串列中某結點的資料,只需要通過查詢演算法找到要更改結點的位置,然後直接更改該結點的資料域即可。

實現程式碼:
  1. //在以body作為頭結點的連結串列中將資料域為oldElem的結點,資料域改為newElem
  2. void amendElem(component * array,int body,char oldElem,char newElem){
  3. int add=selectElem(array, body, oldElem);
  4. if (add==-1) {
  5. printf("無更改元素");
  6. return;
  7. }
  8. array[add].data=newElem;
  9. }

靜態連結串列中插入結點

繼續上邊的例子,插入一個結點,例如該結點的資料域為 e,插入到第 3 的位置:
  1. 首先從備用連結串列中申請空間儲存資料元素 e;
  2. 由於要將 e 結點插入到第 3 的位置上,所以要找到 b 結點,將 b 結點的遊標賦值給 e 結點;
  3. 最後將 e 結點所在位置的下標給 b 結點的遊標;

實現程式碼(在理解靜態連結串列的儲存結構的基礎上):
  1. //向連結串列中插入資料,body表示連結串列的頭結點在陣列中的位置,add表示插入元素的位置,a表示要插入的資料
  2. void insertArr(component * array,int body,int add,char a){
  3. int tempBody=body;//tempBody做遍歷結構體陣列使用
  4. //找到要插入位置的上一個結點在陣列中的位置
  5. for (int i=1; i<add; i++) {
  6. tempBody=array[tempBody].cur;
  7. }
  8. int insert=mallocArr(array);//申請空間,準備插入
  9. array[insert].cur=array[tempBody].cur;//首先要插入結點的遊標等於要插入位置的上一個結點的遊標
  10. array[insert].data=a;
  11. array[tempBody].cur=insert;//然後讓上一結點的遊標等於插入結點所在陣列中的位置的下標
  12. }
程式碼執行效果:

靜態連結串列做刪除操作

靜態連結串列中刪除結點,要實現兩步操作:從連結串列上摘下結點後,將該結點連結到備用連結串列上,以備下次使用。 注:被摘除結點中的資料不需要手動刪除,待下次使用時,會被新的資料域將舊資料覆蓋點。 例如,在(a,b,c,d,e)連結串列中,刪除資料域為 ‘a’ 的結點:

實現程式碼:
  1. //刪除結點函式,a 表示被刪除結點中資料域存放的資料
  2. void deletArr(component * array,int body,char a){
  3. int tempBody=body;
  4. //找到被刪除結點的位置
  5. while (array[tempBody].data!=a) {
  6. tempBody=array[tempBody].cur;
  7. //當tempBody為0時,表示連結串列遍歷結束,說明連結串列中沒有儲存該資料的結點
  8. if (tempBody==0) {
  9. printf("連結串列中沒有此資料");
  10. return;
  11. }
  12. }
  13. //執行到此,證明有該結點
  14. int del=tempBody;
  15. tempBody=body;
  16. //找到該結點的上一個結點,做刪除操作
  17. while (array[tempBody].cur!=del) {
  18. tempBody=array[tempBody].cur;
  19. }
  20. //將被刪除結點的遊標直接給被刪除結點的上一個結點
  21. array[tempBody].cur=array[del].cur;
  22. freeArr(array, del);
  23. }
在該函式中,呼叫了一個freeArr函式,它的作用是回收被刪除結點所佔用的空間,將此空間連結到備用連結串列中,以備下次分配使用。(自己實現的free函式)

freeArr函式實現程式碼:
  1. void freeArr(component * array,int k){
  2. array[k].cur=array[0].cur;
  3. array[0].cur=k;
  4. }

刪除資料域為 ’a’ 結點的執行效果圖:

完整實現程式碼

  1. #include <stdio.h>
  2. #define maxSize 7
  3. typedef struct {
  4. char data;
  5. int cur;
  6. }component;
  7. //將結構體陣列中所有分量連結到備用連結串列中
  8. void reserveArr(component*array);
  9. //初始化靜態連結串列
  10. int initArr(component*array);
  11. //向連結串列中插入資料,body表示連結串列的頭結點在陣列中的位置,add表示插入元素的位置,a表示要插入的資料
  12. void insertArr(component * array,int body,int add,char a);
  13. //刪除連結串列中含有字元a的結點
  14. void deletArr(component * array,int body,char a);
  15. //查詢儲存有字元elem的結點在陣列的位置
  16. int selectElem(component * array,int body,char elem);
  17. //將連結串列中的字元oldElem改為newElem
  18. void amendElem(component * array,int body,char oldElem,char newElem);
  19. //輸出函式
  20. void displayArr(component * array,int body);
  21. //自己需要實現的malloc和free函式
  22. int mallocArr(component * array);
  23. void freeArr(component * array,int k);
  24. int main() {
  25. componentarray[maxSize];
  26. int body=initArr(array);
  27. printf("靜態連結串列為:\n");
  28. displayArr(array, body);
  29. printf("在第3的位置上插入結點‘e’:\n");
  30. 相關推薦

    靜態連結串列C語言實現

    邏輯結構上相鄰的資料元素,儲存在指定的一塊記憶體空間中,資料元素只允許在這塊記憶體空間中隨機存放,這樣的儲存結構生成的連結串列稱為靜態連結串列。 靜態連結串列和動態連結串列的區別:靜態連結串列限制了資料元素存放的位置範圍;動態連結串列是整個記憶體空間。 圖1 靜態連結

    圖 | 儲存結構:鄰接表、鄰接多重表、十字連結串列C語言實現

    上一節介紹瞭如何使用順序儲存結構儲存圖,而在實際應用中最常用的是本節所介紹的鏈式儲存結構:圖中每個頂點作為連結串列中的結點,結點的構成分為資料域和指標域,資料域儲存圖中各頂點中儲存的資料,而指標域負責表示頂點之間的關聯。 使用鏈式儲存結構表示圖的常用方法有 3 種:鄰接表、

    連結串列C語言實現 含動態記憶體分配

    分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

    知識點13:手寫程式碼-倒轉連結串列c語言實現

    寫在前面的廢話:筆記本壞掉了,一插入8g的記憶體卡就開不了機,而不插入的話可以開機,但是又啟動不了AS。不知道是記憶體卡的問題還是電腦介面的問題,想哭。這段時間要等同學帶他的電腦過來幫我測試,所以關於Android的內容暫時是寫不了的了~ 然後,秋招火爆到來,這段時間除了一邊繼續學習嵌

    稀疏矩陣——三元組十字連結串列C語言實現

    粗淺學習稀疏矩陣——三元組十字連結串列。 程式碼實現了新建矩陣、矩陣相加、矩陣逆置和矩陣列印在螢幕上。 慚愧於命名規範和程式設計水平,不足的地方請大牛們多多指教: 直接上程式碼 crosslist.h #ifndef _crosslist_h_ #define

    關於連結串列C語言實現(中級)

    多項式加減法(實驗名稱) 一、實驗目的 掌握單鏈表應用:用連結串列表示多項式,並實現多項式的加減運算。 二、實驗內容 設計一個一元稀疏多項式簡單的加減法計算器,要求: (1)和多項式仍然佔用原來的結點空間,並輸出和多項式。 (2)多項式按照指數遞增的順序輸入,使用者輸入的多項式

    關於連結串列C語言實現(初級)

    好好努力堅持吧,大概演算法什麼的,會是能貫穿自己一輩子的事情 連結串列操作(實驗名稱) 一、實驗目的 掌握連結串列的基本演算法並完成對連結串列各個功能的實現 二、實驗內容 連結串列的基本運算實現,要求至少具有以下功能: (1)連結串列建立 (2)插入運算 (3)刪除運算

    資料結構學習筆記-迴圈連結串列C語言實現

      迴圈連結串列的概念主要就是讓單鏈表的尾節點的指標不為空並且指向頭節點。像這樣的迴圈連結串列和普通單鏈表除了判斷條件幾乎沒有任何區別,判斷條件就是從p->next是否為空改為p->next是否等於頭節點,如果等於頭節點則迴圈結束。#include <std

    連結串列c語言實現以及根據linux核心中連結串列實現過程

    轉自 : http://blog.csdn.net/lickylin/article/details/8010618 連結串列,就是用一組任意的儲存單元儲存線性表元素的一種資料結構。連結串列又分為單鏈表、雙向連結串列和迴圈連結串列等。 下面程式碼是連結串列的兩種實現方式

    (PAT乙級)1025 反轉連結串列C語言實現

    總結: 1、首先要有hash雜湊思想,關鍵字是首地址,對應到的陣列內可以查詢到首地址對應的數值和下一地址。這樣可以構成一組資料的輸入。 2、還應該考慮輸入樣例中有不在連結串列中的結點的情況。所以用個sum計數統計在連結串列裡的有效節點。注意連結串列的最後為空,所以對應

    迴圈連結串列(約瑟夫環)的建立C語言實現

    連結串列的使用,還可以把連結串列的兩頭連線,形成了一個環狀連結串列,稱為迴圈連結串列。和它名字的表意一樣,只需要將表中最後一個結點的指標指向頭結點,就形成了一個環。 圖1 迴圈連結串列 迴圈連結串列和動態連結串列相比,唯一的不同就是迴圈連結串列首尾相連,其他都完全一

    將兩個非遞減的有序連結串列合併為一個非遞增的有序連結串列C語言程式設計實現

    將兩個非遞減的有序連結串列合併為一個非遞增的有序連結串列。要求結果連結串列仍使用原來兩個連結串列的儲存空間, 不另外佔用其它的儲存空間。表中允許有重複的資料。 #include<stdio.

    數據結構8: 雙向鏈表(雙向循環鏈表)的建立C語言實現

    clas truct 開始 麻煩 使用 解釋 display 表頭 後繼 之前接觸到的鏈表都只有一個指針,指向直接後繼,整個鏈表只能單方向從表頭訪問到表尾,這種結構的鏈表統稱為 “單向鏈表”或“單鏈表”。 如果算法中需要頻繁

    數據結構11: 棧(Stack)的概念和應用C語言實現

    next ret 額外 轉換 lib 順序存儲 順序棧 就是 函數 棧,線性表的一種特殊的存儲結構。與學習過的線性表的不同之處在於棧只能從表的固定一端對數據進行插入和刪除操作,另一端是封死的。 圖1 棧結構示意圖 由於棧只有一邊開口存取數據,稱開口的那一端

    順序表(線性表的順序儲存結構)C語言實現

    1.邏輯結構上呈線性分佈的資料元素在實際的物理儲存結構中也同樣相互之間緊挨著,這種儲存結構稱為線性表的順序儲存結構。 也就是說,邏輯上具有線性關係的資料按照前後的次序全部儲存在一整塊連續的記憶體空間中,之間不存在空隙,這樣的儲存結構稱為順序儲存結構。使用順序儲存結構儲存的資料,第一個元素所在的地

    LeetCode203移除連結串列元素C語言

    /** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* removeElements

    Canny邊緣檢測演算法原理C語言實現詳解

    Canny運算元是John Canny在1986年提出的,那年老大爺才28歲,該文章發表在PAMI頂級期刊上的(1986. A computational approach to edge detection. IEEE Transactions on Pattern Analy

    連結串列C語言

    1、連結串列的定義 typedef struct stu { int num; struct stu *next; }stu,*student; 2、連結串列的建立         連結串列是用指標連線起來的線性表,對於連結串列的每個結點,都要給它動態分配記憶體,這

    回溯法(八皇后問題)C語言實現

           回溯法,又被稱為“試探法”。解決問題時,每進行一步,都是抱著試試看的態度,如果發現當前選擇並不是最好的,或者這麼走下去肯定達不到目標,立刻做回退操作重新選擇。這種走不通就回退再走的方法就是回溯法。 回溯VS遞迴 很多人認為回溯和遞迴是一樣的,其實不然。在回溯

    連結串列C語言)刪除、插入(頭插法)、清空等操作

    幾個重要知識點: 一: L = (LinkList)malloc(sizeof(LNode)); L->next = NULL; 在給節點分配記憶體後,一定要將next指標賦值為null。 二: Status ListInsert(LinkList &