靜態鏈表


靜態鏈表:線性存儲結構的一種,兼顧順序表和鏈表的優點,是順序表和鏈表的升級;靜態鏈表的數據全部存儲在數組中(順序表),但存儲的位置是隨機的,數據直接的一對一關系是通過一個整型變量(稱為“游標”,類似指針的功能)維持。

1. 靜態鏈表中的節點

    數據域:用於存儲數據元素的值

    游標:即數組下標,表示直接后繼元素所在數組中的位置

typedef struct
{
  int data; //靜態鏈表節點中的數據
  int cur;   //靜態鏈表節點中的游標
}component;

例:使用靜態鏈表存儲數據元素4、5、6,過程如下:

  注:通常靜態鏈表會將第一個數據元素放到數組下標為1(即a[1])的位置中。

     圖中從a[1]存儲的數據元素4開始,通過存儲的游標變量3,可以在a[3]中找到元素4的直接后繼元素5;通過元素a[3]存儲的游標變量6,可在在a[6]中找到元素5的直接后繼元素6;這樣一直到某元素的游標變量為0截止(a[0]默認不存儲數據元素)

2. 備用鏈表

  靜態鏈表中,除了數據本身通過游標組成鏈表外,還需要有一條連接各個空閑位置的鏈表,稱為備用鏈表。

  作用:回收數組中未使用或者之前使用過(現在不用)的存儲空間,留待后期使用。即靜態鏈表使用數組申請的物理空間中,存在兩個鏈表,一條連接數據,另一條連接數組中為使用的空間。

  注:通常備用鏈表的表頭位於數組下標為0(a[0])的位置,而數據鏈表的表頭位於數組下標為1(a[1])的位置。

  靜態鏈表中設置備用鏈表的好處是,可以清楚地知道數組中是否有空閑位置,以便數據鏈表添加新數據時使用。比如,若靜態鏈表中數組下標為 0 的位置上存有數據,則證明數組已滿。

3 靜態鏈表的實現

  在數據鏈表未初始化之前,數組中所有位置都處於空閑狀態,所以都鏈接在備用鏈表上。(圖1)

  向靜態鏈表中添加數據時,需提前從備用鏈表中摘除結點,讓新數據使用。

  備用鏈表摘除節點最簡單的方法是摘除a[0]的直接后繼節點(即摘除a[1]的游標2);同樣,向備用鏈表中添加空閑節點也是添加作為a[0]新的直接后繼節點(圖二中a[1]為a[0]新的直接后繼結點(游標為2)、圖三中a[2]為a[0]新的直接后繼結點(游標為3)、圖四中a[3]為a[0]新的直接后繼結點(游標為4))。因為 a[0] 是備用鏈表的第一個節點,我們知道它的位置,操作它的直接后繼節點相對容易,無需遍歷備用鏈表,耗費的時間復雜度為為O(1)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 #define maxSize 6
 5 
 6 typedef struct
 7 {
 8     int data;
 9     int cur;  //游標
10 }component;
11 
12 /*************************************************************************
13 創建備用鏈表
14 *****************************************************************************/
15 void reserveArr(component *array)
16 {
17     int i;
18     for(i=0;i<maxSize;i++)
19     {
20         array[i].cur=i+1;   //將每個數組分量鏈接到一起
21     }
22     array[maxSize-1].cur=0; //鏈表最后一個節點的游標為0
23 }
24 
25 /********************************************************
26 提取分配空間
27 若備用鏈表為非空,則返回分配的節點下標,否則返回0(當分配最后一個節點時,該節點的游標值為0)
28 ********************************************************/
29 int mallocArr(component *array)
30 {
31     int i=array[0].cur;
32     
33     if(array[0].cur)
34     {
35         //array[0].data=0;
36         array[0].cur=array[i].cur;
37     }
38     return i;
39 }
40 
41 /***************************************************************************
42 初始化靜態鏈表
43 ****************************************************************************/
44 int initArr(component *array)
45 {
46     int body,tempBody,i,j;
47     reserveArr(array);
48     body=mallocArr(array);
49     tempBody=body;  //聲明一個變量把它當指針使,指向鏈表的最后一個節點,因為鏈表為空,所以和頭結點重合
50     for(i=1;i<4;i++)
51     {
52         j=mallocArr(array);  //從備用鏈表中拿出空閑的分量
53         array[tempBody].cur=j;//將申請的空閑分量鏈接在鏈表的最后一個結點后面
54         array[j].data=i;  //給新申請的分量數據域初始化
55         tempBody=j;  //將指向鏈表最后一個結點的指針后移
56     }
57     array[tempBody].cur=0;  //新的鏈表最后一個結點的指針設為0
58     return body;
59 }
60 
61 void displayArr(component *array,int body)
62 {
63     int tempBody=body; //tempBody准備遍歷使用
64     while(array[tempBody].cur)
65     {
66         printf("%d,%d\n",array[tempBody].data,array[tempBody].cur);
67         tempBody=array[tempBody].cur;
68     }
69     printf("%d,%d\n",array[tempBody].data,array[tempBody].cur);
70 }
71 
72 int main()
73 {
74     int body;
75     component array[maxSize];
76     body=initArr(array);
77     printf("static link:\n");
78     displayArr(array,body);
79 
80     system("pause");
81     return 0;
82 }

4 靜態鏈表中添加一個元素

void Insert(component *array,int body,int add,int a)//body鏈表頭結點在數組中的位置,add插入元素的位置,a插入的元素
{
    int tempBody=body;
    int i,insert;
    for(i=1;i<add;i++)
    {
        tempBody=array[tempBody].cur;
    }
    insert=mallocArr(array);
    array[insert].data=a;
    array[insert].cur=array[tempBody].cur;
    array[tempBody].cur=insert;
}

5 靜態鏈表刪除元素

    1.將存有目標元素的節點從數據鏈表中摘除;

   2.將摘除節點添加到備用鏈表,以便下次再用;

//備用鏈表回收空間的函數,其中array為存儲數據的數組,k表示未使用節點所在數組的下標
void freeArr(component * array,int k)
{ array[k].cur
=array[0].cur; array[0].cur=k; } //刪除結點函數,a 表示被刪除結點中數據域存放的數據 void deletArr(component * array,int body,char a)
{
int tempBody=body; //找到被刪除結點的位置 while (array[tempBody].data!=a)
{ tempBody
=array[tempBody].cur; //當tempBody為0時,表示鏈表遍歷結束,說明鏈表中沒有存儲該數據的結點 if (tempBody==0)
{ printf(
"鏈表中沒有此數據"); return; } } //運行到此,證明有該結點 int del=tempBody; tempBody=body; //找到該結點的上一個結點,做刪除操作 while (array[tempBody].cur!=del)
{ tempBody
=array[tempBody].cur; } //將被刪除結點的游標直接給被刪除結點的上一個結點 array[tempBody].cur=array[del].cur; //回收被摘除節點的空間 freeArr(array, del); }

6 靜態鏈表中查找元素

/********************************************************
在以body作為頭結點的鏈表中查找數據域為elem的結點在數組中的位置
*****************************************************/
int SelectElem(component * array,int body,char elem){
    int tempBody=body;
    while (array[tempBody].cur!=0) //當游標值為0時,表示鏈表結束
   {
        if (array[tempBody].data==elem) {
            return tempBody;
        }
        tempBody=array[tempBody].cur;
    }
    return -1;//返回-1,表示在鏈表中沒有找到該元素
}

7 靜態鏈表中更改數據

/********************************************************
在以body作為頭結點的鏈表中將數據域為oldElem的結點,數據域改為newElem
**********************************************************/
void amendElem(component * array,int body,char oldElem,char newElem)
{
    int add=selectElem(array, body, oldElem);
    if (add==-1)
   {
        printf("無更改元素");
        return;
    }
    array[add].data=newElem;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM