【數據結構】單鏈表&&靜態鏈表詳解和代碼實例


喜歡的話可以掃碼關注我們的公眾號哦,更多精彩盡在微信公眾號【程序猿聲】

01 單鏈表(Singly Linked List )

1.1 什么是單鏈表?

單鏈表是一種鏈式存儲的結構。它動態的為節點分配存儲單元。當有節點插入時,系統動態的為結點分配空間。在結點刪除時,應該及時釋放相應的存儲單元,以防止內存泄露。由於是鏈式存儲,所以操作單鏈表時,必須知道頭結點或者頭指針的位置。並且,在查找第i個節點時,必須找到第i-1個節點。

1.2 單鏈表的存儲結構代碼描述

對於鏈式存儲,通過上一節的講解相信大家已經了解得夠清楚了。如下圖所示:

下面我們來看看單鏈表存儲是如何用代碼來實現的。

1//單鏈表的存儲結構C語言代碼
2typedef struct SListNode
3{

4    datatype data;    //數據域
5    struct SListNode * pnext;//指針域
6}SLinkList;

由上面的結構我們可以看出,一個節點由存放數據的數據域和存放地址的指針域組成。假如p指向了第i個節點,那么p->data就是該節點存放的數據,而p->pnext自然就是指向下一個節點的指針。如下圖所示:

那么接下來我們看看單鏈表的各個操作具體實現吧。(只講幾個關鍵步驟)
備注:下面的代碼基於這樣的一個單鏈表:

  • 有一個頭指針phead
  • 有一個頭結點node
  • 頭指針指向頭結點,頭結點位置記為0

1.3 單鏈表的讀取

在拿到頭指針以后,單鏈表的讀取也並非一件難事。一開始設置一個計數變量,不斷遍歷鏈表,讓計數器自增。找到合適的位置將數據讀取出來。具體代碼實現如下:

 1#define status bool
2#define ERROR false
3#define OK true
4/*
5 * 函數功能:獲取位置index節點的數據
6 * 參數說明:phead鏈表頭結點,e用來獲取的變量,index索引
7*/

8
9status GetSListIndexNode(Node * phead,DType *e, int index)
10
{
11    int icount = 0//計數器
12    //注:0號位為頭結點,頭結點不存放任何數據
13    if (phead->pnext == nullptr || index < 1 || index > GetSListLength()/*此處為鏈表長度*/)
14    {
15        return ERROR; //異常 處理
16    }
17    while (phead->pnext != nullptr)
18    {
19        icount++;
20        phead = phead->pnext;
21        if (icount == index)
22        {
23            *e = phead->data;
24            return OK;
25        }
26    }
27    return ERROR;
28}

1.4 單鏈表的插入

1.4.1 指定位置后插

其實鏈表的插入和刪除都是很簡單的操作,初學者只要抓住指針指向的節點,並加以區分開來,就很easy了。如下圖:

圖中,假如此時p指向了我們要插入的節點的位置。那么,怎樣把我們的S節點給插入到p指向的節點之后?在這里我們先不要驚動p以及p后面的節點:

  1. 我們先讓S節點指向p之后的節點(步驟①)
  2. 之后我們切斷p和p后面那個節點的關系(步驟②)
  3. 最后讓p節點的指針域指向s節點(步驟③),搞定

算法描述:

  1. 聲明一個指針p指向鏈表頭結點,向后遍歷p=p->next,找到正確的位置。
  2. 新建一個結點s。
  3. s->next = p->next ①
  4. p->next = s ②③
    具體代碼如下:
 1#define status bool
2#define ERROR false
3#define OK true
4/*
5 * 函數功能:指定位置后插
6 * 參數說明:phead鏈表頭結點,IData插入的數據,index索引
7*/

8status InsertSListNodeFront(Node * phead, DType IData, int index)
9
{
10    if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
11    {
12        return ERROR; //異常 處理
13    }
14    int iCount = 0//計數器
15    Node<DType> * q = nullptr//備用
16    while (phead->pnext != nullptr)
17    {
18        iCount++;
19        q = phead;
20        phead = phead->pnext;
21        if ( iCount == index )
22        {
23            Node<DType> * p = new Node<DType>;
24            p->data = IData;
25            p->pnext = phead;
26            q->pnext = p;   //前插
27            return OK;
28        }
29    }
30    return ERROR;
31}
1.4.2 指定位置前插

咳咳,聰明的小伙伴,用腦子想想。指定位置前插 == 指定位置的前一個位置進行后插。懂了吧?直接看具體代碼:

 1/*
2 * 函數功能:指定位置后插
3 * 參數說明:phead鏈表頭結點,IData插入的數據,index索引
4*/

5status InsertSListNodeBack(Node * phead, DType IData, int index)
6
{
7    if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
8    {
9        return ERROR; //異常 處理
10    }
11    int iCount = 0//計數器
12    Node<DType> * q = nullptr//備用
13    while (phead->pnext != nullptr)
14    {
15        iCount++;
16        q = phead;
17        phead = phead->pnext;
18        if (iCount == index)
19        {
20            Node<DType> * p = new Node<DType>;
21            q = phead;
22            phead = phead->pnext; //后插就是后一個節點的前插咯
23            p->data = IData;
24            p->pnext = phead;
25            q->pnext = p;   
26            return OK;
27        }
28    }
29    return ERROR;
30}

1.5 單鏈表的刪除

單鏈表的刪除其實也是很簡單。只要比如要刪除p指向的節點,只需要讓p之前的節點的指針域直接指向p之后的節點,再把p給free就OK了。如下圖:

算法描述:

  1. 聲明一個指針p指向鏈表頭結點,向后遍歷p=p->next,找到要刪除的節點位置。
  2. q = p->next
  3. p->next = q->next ①②
  4. free(q) ③④

具體代碼如下:

 1/*
2 * 函數功能:指定位置后插
3 * 參數說明:phead鏈表頭結點,IData獲取刪除的數據,index索引
4*/

5//刪除指定位置節點(e獲取刪除元素)
6template <typename DType>
7status DeleteSListIndexNode(Node * phead, DType *e, int index)
8
{
9    int i = 0//計數器
10    Node<DType> * q = nullptr;
11    if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
12    {
13        return ERROR; //異常 處理
14    }
15    while (phead->pnext != nullptr)
16    {
17        i++;
18        q = phead; //保存備用
19        phead = phead->pnext;
20        if (i == index)
21        {
22            *e = phead->data;
23            q->pnext = phead->pnext; //刪除出局
24            return OK;
25        }
26    }
27    return ERROR;
28}

代碼應該不難,相信大家都能很容易看懂。

1.6.1 單鏈表的完整代碼

好了,前面介紹了幾個重要的操作,接下來請大家看看完整的代碼吧。小編為了使用方便,就用C++的class和template將整個鏈表封裝到了一個類里面,通過模板實現泛型編程。

 1/*
2 * 文件名:SingleLinkList.h
3 * 說明 :類的各種聲明
4 */

5#pragma once //VC編譯器防止頭文件被重復包含的一條預編譯指令
6
7#define status bool
8#define OK true
9#define ERROR false
10#define YES true
11#define NO false
12
13template <typename DType>
14class Node
15{

16public:
17    DType data;
18    Node * pnext;
19};
20
21template <typename DType>
22class CSingleLinkList
23{

24private:
25    Node<DType> *phead; //鏈表頭指針
26public:
27    CSingleLinkList();//構造,類被創建時調用
28    ~CSingleLinkList();//析構,類被銷毀時調用
29public:
30    //初始化鏈表
31    status InitSList();
32    //獲取鏈表長度
33    int GetSListLength();
34    //增加一個節點 前插法
35    status AddSListNodeFront(DType idata);
36    //增加一個節點 后插法
37    status AddSListNodeBack( DType idata);
38    //判斷鏈表是否為空
39    status IsSListEmpty();
40    //獲取指定位置節點值(注意,本程序規定0號為頭節點,e獲取刪除元素)
41    status GetSListIndexNode(DType *e, int index);
42    //刪除指定位置節點(e獲取刪除元素)
43    status DeleteSListIndexNode(DType *e, int index);
44    //查找鏈表中指定值(pindex獲取位置0==>not found)
45    status SearchSListNode(DType SData, int *pindex);
46    //指定位置前插
47    status InsertSListNodeFront(DType IData, int index);
48    //指定位置后插
49    status InsertSListNodeBack(DType IData, int index);
50    //清空鏈表(保留根節點)
51    status ClearSList();
52    //銷毀鏈表(all delete)
53    status DestorySList();
54    //尾部刪除一個元素
55    status DeleteSListNodeBack();
56    //打印鏈表   此函數根據實際情況而定
57    void PrintSList();
58};
59
60/*
61 * 文件名:SingleLinkList.cpp
62 * 說明 :類的各種方法的實現
63 */

64
65#include "SingleLinkList.h"
66#include <stdio.h>
67
68template <typename DType>
69CSingleLinkList<DType>::CSingleLinkList()
70{
71    cout << "鏈表創建" << endl;
72    InitSList();
73}
74template <typename DType>
75CSingleLinkList<DType>::~CSingleLinkList()
76{
77    cout << "鏈表銷毀" << endl;
78    DestorySList();
79}
80//初始化鏈表
81template <typename DType>
82status CSingleLinkList<DType>::InitSList()
83{
84    Node<DType> * ph = new Node<DType>;
85    if (ph != NULL)
86    {
87        ph->pnext = nullptr;
88        this->phead = ph; //頭結點
89        return OK;
90    }
91    return ERROR;
92}
93//獲取鏈表長度(head_node is not included)
94template <typename DType>
95int CSingleLinkList<DType>::GetSListLength()
96{
97    int length = 0;
98    Node<DType> * phead = this->phead;
99    while (phead->pnext != nullptr)
100    {
101        length++;
102        phead = phead->pnext;
103    }
104    return length;
105}
106//增加一個節點 前插法
107template <typename DType>
108status CSingleLinkList<DType>::AddSListNodeFront( DType idata)
109{
110    Node<DType> * pnode = new Node<DType>;
111    if (pnode != NULL)
112    {
113        pnode->data = idata;
114        pnode->pnext = this->phead->pnext;
115        this->phead->pnext = pnode; //掛載
116
117        //printf("pnode = %p  pnode->pnext = %p this->phead->pnext = %p this->phead = %p\n", pnode, pnode->pnext, this->phead->pnext, this->phead);
118        return OK;
119    }
120    return ERROR;
121}
122
123
124//增加一個節點 尾插法
125template <typename DType>
126status CSingleLinkList<DType>::AddSListNodeBack(DType idata)
127{
128    Node<DType> * pnode = new Node<DType>;
129    Node<DType> * phead = this->phead;
130    if (pnode != NULL)
131    {
132        while (phead->pnext != nullptr)
133        {
134            phead = phead->pnext;
135        }
136        pnode->data = idata;
137        pnode->pnext = nullptr;
138        phead->pnext = pnode; //掛載
139        return OK;
140    }
141    return ERROR;
142}
143//判斷鏈表是否為空
144template <typename DType>
145status CSingleLinkList<DType>::IsSListEmpty()
146{
147    if (this->phead->pnext == nullptr)
148    {
149        return YES;
150    }
151    return NO;
152}
153//獲取指定位置節點值(注意,本程序規定0號為頭節點,e獲取節點的值)
154template <typename DType>
155status CSingleLinkList<DType>::GetSListIndexNode(DType *e, int index)
156{
157    Node<DType> * phead = this->phead;
158    int i = 0//計數器
159    if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
160    {
161        return ERROR; //異常 處理
162    }
163    while (phead->pnext != nullptr)
164    {
165        i++;
166        phead = phead->pnext;
167        if (i == index)
168        {
169            *e = phead->data;
170            return OK;
171        }
172    }
173    return ERROR;
174}
175//刪除指定位置節點(e獲取刪除元素)
176template <typename DType>
177status CSingleLinkList<DType>::DeleteSListIndexNode( DType *e, int index)
178{
179    Node<DType> * phead = this->phead;
180    int i = 0//計數器
181    Node<DType> * q = nullptr;
182    if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
183    {
184        return ERROR; //異常 處理
185    }
186    while (phead->pnext != nullptr)
187    {
188        i++;
189        q = phead; //保存備用
190        phead = phead->pnext;
191        if (i == index)
192        {
193            *e = phead->data;
194            q->pnext = phead->pnext; //刪除出局
195            return OK;
196        }
197    }
198    return ERROR;
199}
200//查找鏈表中指定值(pindex獲取位置   0==>not found)
201template <typename DType>
202status CSingleLinkList<DType>::SearchSListNode( DType SData, int *pindex)
203{
204    Node<DType> * phead = this->phead;
205    int iCount = 0;//計數器
206    while (phead->pnext != nullptr)
207    {
208        iCount++;
209        phead = phead->pnext;
210        if (phead->data == SData)
211        {
212            *pindex = iCount;
213            return YES;
214        }
215    }
216    *pindex = 0;
217    return NO;
218}
219//指定位置前插
220template <typename DType>
221status CSingleLinkList<DType>::InsertSListNodeFront(DType IData, int index)
222{
223    Node<DType> * phead = this->phead;
224    if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
225    {
226        return ERROR; //異常 處理
227    }
228    int iCount = 0//計數器
229    Node<DType> * q = nullptr//備用
230    while (phead->pnext != nullptr)
231    {
232        iCount++;
233        q = phead;
234        phead = phead->pnext;
235        if ( iCount == index )
236        {
237            Node<DType> * p = new Node<DType>;
238            p->data = IData;
239            p->pnext = phead;
240            q->pnext = p;   //前插
241            return OK;
242        }
243    }
244    return ERROR;
245}
246//指定位置后插
247template <typename DType>
248status CSingleLinkList<DType>::InsertSListNodeBack( DType IData, int index)
249{
250    Node<DType> * phead = this->phead;
251    if (phead->pnext == nullptr || index < 1 || index > GetSListLength())
252    {
253        return ERROR; //異常 處理
254    }
255    int iCount = 0//計數器
256    Node<DType> * q = nullptr//備用
257    while (phead->pnext != nullptr)
258    {
259        iCount++;
260        q = phead;
261        phead = phead->pnext;
262        if (iCount == index)
263        {
264            Node<DType> * p = new Node<DType>;
265            q = phead;
266            phead = phead->pnext; //后插就是后一個節點的前插咯
267            p->data = IData;
268            p->pnext = phead;
269            q->pnext = p;   
270            return OK;
271        }
272    }
273    return ERROR;
274}
275//清空鏈表(保留根節點)
276template <typename DType>
277status CSingleLinkList<DType>::ClearSList()
278{
279    Node<DType> * phead = this->phead;
280    Node<DType> * q = nullptr//防止那啥,野指針
281    phead = phead->pnext;//保留頭節點
282    while (phead != nullptr)
283    {
284        q = phead;
285        phead = phead->pnext;
286        delete q; //釋放
287    }
288    this->phead->pnext = nullptr;
289    return OK;
290}
291//銷毀鏈表(all delete)
292template <typename DType>
293status CSingleLinkList<DType>::DestorySList()
294{
295    ClearSList();
296    delete this->phead;//釋放頭結點 
297    return OK;
298}
299
300template <typename DType>
301status CSingleLinkList<DType>::DeleteSListNodeBack()
302{
303    Node<DType> * phead = this->phead;
304    Node<DType> * q = nullptr//備用
305    if (phead->pnext == nullptr)
306    {
307        return ERROR; //鏈表都空了還刪雞毛
308    }
309    while (phead->pnext != nullptr)
310    {
311        q = phead;
312        phead = phead->pnext;
313    }
314    q->pnext = nullptr;
315    delete phead;
316
317    return OK;
318
319}
320template <typename DType>
321void CSingleLinkList<DType>::PrintSList()
322{
323    Node<DType> * phead = this->phead;
324    if (phead->pnext == nullptr || phead == nullptr)
325    {
326        cout << "鏈表為空,打印雞毛" << endl;
327        return;
328    }
329    int i = 1;
330    cout << "===============print list================" << endl;
331    while (phead->pnext != nullptr)
332    {
333        phead = phead->pnext;
334        cout <<"node[" << i++ << "] = " << phead->data<<endl;
335    }
336}
337
338/*
339 * 文件名:SingleLinkListTest.cpp
340 * 說明 :測試代碼
341 */

342
343 #include <iostream>
344#include "SingleLinkList.h"
345#include "SingleLinkList.cpp"
346
347using namespace std;
348
349int main()
350
{
351    CSingleLinkList<int> * pMySList = new CSingleLinkList<int>;
352    cout << pMySList->IsSListEmpty() << endl;
353    pMySList->AddSListNodeFront(111);
354    pMySList->AddSListNodeFront(222);
355    pMySList->AddSListNodeFront(333);
356
357    cout << "鏈表長度" << pMySList->GetSListLength() << endl;
358
359    pMySList->PrintSList();
360
361    pMySList->AddSListNodeBack(444);
362    pMySList->AddSListNodeBack(555);
363    pMySList->AddSListNodeBack(666);
364
365    pMySList->PrintSList();
366
367    cout << pMySList->IsSListEmpty() << endl;
368    cout << "鏈表長度" << pMySList->GetSListLength() << endl;
369
370    int GetElem, GetIndex;
371    pMySList->GetSListIndexNode(&GetElem, 2);
372    cout << "Got Elem = " << GetElem << endl;
373
374    pMySList->GetSListIndexNode(&GetElem, 6);
375    cout << "Got Elem = " << GetElem << endl;
376
377    pMySList->GetSListIndexNode(&GetElem, 4);
378    cout << "Got Elem = " << GetElem << endl;
379
380    pMySList->DeleteSListIndexNode(&GetElem, 1);
381    cout << "del Elem = " << GetElem << endl;
382    pMySList->DeleteSListIndexNode(&GetElem, 3);
383    cout << "del Elem = " << GetElem << endl;
384
385
386    pMySList->PrintSList();
387
388    pMySList->SearchSListNode(555, &GetIndex);
389    cout << "Search Index = " << GetIndex << endl;
390    pMySList->SearchSListNode(111, &GetIndex);
391    cout << "Search Index = " << GetIndex << endl;
392    pMySList->SearchSListNode(666, &GetIndex);
393    cout << "Search Index = " << GetIndex << endl;
394
395    pMySList->InsertSListNodeFront(3331);
396    pMySList->InsertSListNodeFront(4444);
397
398    pMySList->PrintSList();
399
400    pMySList->InsertSListNodeBack(7773);
401    pMySList->InsertSListNodeBack(8885);
402
403    pMySList->PrintSList();
404
405    pMySList->DeleteSListNodeBack();
406    pMySList->PrintSList();
407    pMySList->DeleteSListNodeBack();
408    pMySList->PrintSList();
409    pMySList->DeleteSListNodeBack();
410    pMySList->PrintSList();
411
412    return 0;
413}
414
415

代碼如果有不正確的地方,歡迎大家來指正哈。

02 靜態鏈表(circular linked list)

2.1 什么是靜態鏈表?

我們把線性表的元素存放在數組中,這些元素由兩個域組成:

  • 數據域data
  • 指針域cur

數據域是存放數據的,而指針域,這里和鏈表不同是,它存的不再是指向下一個節點的內存地址。而是下一個節點在數組中的下標。我們就把這種用數組描述的鏈表稱為靜態表,該方法也稱之為游標實現法。如下圖所示:

由上圖我們需要注意以下幾點:

  • 我們對數組的第一個元素和最后一個元素做特殊處理,不存放數據。
  • 把未使用的數組元素稱為備用鏈表。
  • 數組的第一個元素(下標為0)的cur域存放備用鏈表第一個節點的下標。
  • 數組的最后一個元素的cur域存放第一個有數據的節點的下標,相當於鏈表中頭結點的存在。鏈表為空時,其值為0。

如下圖:

引出的問題:數組的長度定義的問題,無法預支。所以,為了防止溢出,我們一般將靜態表開得大一點。

2.2 靜態鏈表存儲的代碼描述

基於上面的講解,我們來看看代碼是怎么描述這種存儲結構的。

1//---------線性表的靜態單鏈表存儲結構--------
2#define MAXSIZE 1000 /*假設鏈表最大長度為1000*/
3typedef struct
4{

5    datatype data;
6    int cur;   //為0時表示無指向
7}SLinkList[MAXSIZE];

接下來我們講解幾個重要的操作實現。

2.3 靜態鏈表的插入操作

前面我們講動態鏈表的時候說過,增加和刪除一個節點我們可以用malloc()和free()函數(C++可用new和delete)來實現。但是現在由於我們操作的是靜態表,它可是用數組存的,可沒有這種操作了。因此我們首先來自己實現一個靜態表的malloc和free。

那么怎么辨別數組中哪些空間沒有被使用呢?一個好的解決辦法是,將所有未使用或者被刪除的空間串成一個備用鏈表。插入節點時便可以從備用鏈表獲取第一個未使用的空間的下標。因此我們在初始化的時候會做這樣的工作:

 1void SListInit(SLinkList space)
2
{
3    int i;
4    for(i = 0; i < MAXSIZE; i++)
5        space[i].cur = i+1//將所有結點鏈入備用鏈表
6    //備用鏈表頭指針鏈像第二個結點
7    space[0].cur = space[1].cur; 
8    //第一個結點作為鏈表的頭結點  
9    space[1].cur = 0;              
10}

分配內存

 1/分配備用鏈表的一個結點,返回下標
2//若為0,則說明備用鏈表用完
3int Malloc_SL(SLinkList space)
4
{
5    int i = space[0].cur;
6    //判斷備用鏈表是否非空
7    if(space[0].cur)    
8        //備用鏈表頭指針指向第二個空結點
9        space[0].cur = space[i].cur; 
10
11    return i;    //返回第一個空結點
12}

上面的代碼應該是沒有難度的。寫完了這個函數,我們來看看靜態表中具體如何插入:

 1//在鏈表的第i個位置插入元素e
2void SlistInsert(SLinkList space, int i, ElemType e)
3
{
4    //超出范圍
5    if(i < 1 || i > SListLength(space)+1
6        return;
7    int k = 1, j;
8    //使k指示要插入的結點的前一個結點
9    for(j = 0; j <i-1; j++) 
10        k = space[k].cur;
11
12    int v = Malloc_SL(space);
13    if(v)     //如果有空間
14    {
15        space[v].data = e;
16        space[v].cur = space[k].cur;
17        space[k].cur = v;  //鏈入鏈表
18    }
19}

注意幾點:

  • 首先我們讓k指向了要插入節點(記為X)的前一個位置(記為Y節點),前插法。
  • 然后我們在靜態表內申請空間,存放新的節點(記為N)。
  • 把數據放進新申請的節點里面。
  • 新節點N的cur域指向X節點,然后讓Y節點指向N節點。

該過程不難理解。就不上圖了……

2.4 靜態鏈表的刪除操作

刪除同樣需要自己實現free函數,我們來看看代碼:

回收內存

1//將下標為k的空閑結點回收到備用鏈表
2void Free_SL(SLinkList space, int k)
3
{
4    //將備用鏈表鏈到k之后
5    space[k].cur = space[0].cur;  
6    //將k鏈到備用鏈表頭之后
7    space[0].cur = k;               
8}

刪除以后記得把空間重新掛載到備用鏈表上以便下一次使用。下面我們實現刪除的代碼:

 1//刪除第i個位置的元素
2void SListDelete(SLinkList space, int i)
3
{   //超出范圍退出
4    if(i < 1 || i > SListLength(space))  
5        return ;
6    int k = 1, j;
7     //使k指示要刪除的結點的前一個結點
8    for(j = 0; j <i-1; j++)  
9        k = space[k].cur;
10
11    int temp = space[k].cur;
12    space[k].cur = space[temp].cur;
13    Free_SL(space, temp);
14}

其實代碼也很好理解了。假如X、Y、Z……等等排列,我們要刪除Y。無非就是告訴X,你不要指向Y了,你直接指向Z,然后我們再把Y給free了。就直接變成了X、Z……簡單吧。

2.5 靜態鏈表的完整代碼

熬了一個下午,終於寫完了.哈哈,用了C++的類模板封裝了一個靜態鏈表,簡單的增刪查改功能都有了.具體可以看代碼:

StaticLinkList.h

 1#pragma once
2#include <iomanip>
3
4#define MAXSIZE 100
5
6#define status bool
7#define YES true
8#define NO false
9#define OK true
10#define ERROR false
11
12template <typename DATATYPE>
13class Component
14{

15public:
16    DATATYPE data; //數據域
17    int cur;       //cur域,指向下一個元素的下標
18};
19
20
21template <typename DATATYPE>
22class CStaticLinkList
23{

24public:
25    Component<DATATYPE>  StaticLinkList[MAXSIZE];  //靜態表
26//自定義malloc和free
27public:
28    int MallocNodeSSL();
29    status FreeNodeSSL(int index);
30public:
31    status InitList()//初始化靜態表
32    status BackAddList( DATATYPE AddData)//尾增加
33    status InsertNodeList(DATATYPE InsertData, int index);//指定位置插入
34    status DeleteNodeList(DATATYPE *DelData, int index)//指定位置刪除
35    int SearchList(DATATYPE sData);       //搜索數據為sData的節點,返回其在數組中的下標,0表示失敗
36    status GetIndexList(DATATYPE *gData, int index);//獲取指定索引的節點數據
37    int GetLengthList()//獲取靜態表的長度
38    status ClearList()//清空靜態表
39    status IsEmptyList()//判斷靜態表是否為空
40    status IsFullList()//判斷靜態表是否滿了
41    void PrintList()//打印靜態表,此函數根據實際情況編寫
42
43public:
44    CStaticLinkList();
45    ~CStaticLinkList();
46};

StaticLinkList.cpp

 1#include "StaticLinkList.h"
2
3template <typename DATATYPE>
4CStaticLinkList<DATATYPE>::CStaticLinkList()
5{
6    cout << "===========靜態表創建===========" << endl;
7    InitList();
8}
9
10template <typename DATATYPE>
11CStaticLinkList<DATATYPE>::~CStaticLinkList()
12{
13    cout << "===========靜態表銷毀===========" << endl;
14}
15
16template <typename DATATYPE>
17int CStaticLinkList<DATATYPE>::MallocNodeSSL()
18{
19    int index = StaticLinkList[0].cur; //把備用鏈表第一個節點拿出來用
20    if (StaticLinkList[0].cur) //判斷是否還有位置
21    {
22        StaticLinkList[0].cur = StaticLinkList[index].cur; //讓備用鏈表第二個節點上來頂替第一個的位置
23    }
24
25    return index; //返回0表示分配失敗
26}
27
28template <typename DATATYPE>
29status CStaticLinkList<DATATYPE>::FreeNodeSSL(int index)
30{
31    //將刪除節點掛接到備用鏈表上
32    this->StaticLinkList[index].cur = this->StaticLinkList[0].cur;
33    this->StaticLinkList[0].cur = index;
34
35    return OK;
36}
37
38template <typename DATATYPE>
39status CStaticLinkList<DATATYPE>::InitList()
40{
41    int i;
42    for (i = 0; i < MAXSIZE - 1; i++)
43    {
44        StaticLinkList[i].cur = i + 1;//全部塞入備用鏈表
45    }
46    StaticLinkList[MAXSIZE - 1].cur = 0;/*因為目前靜態表為空,最后一個節點的cur域為0*/
47    return OK;
48}
49
50template <typename DATATYPE>
51status CStaticLinkList<DATATYPE>::BackAddList(DATATYPE AddData) //尾增加
52{
53    if (IsFullList())
54    {
55        return ERROR;
56    }
57    int index = MAXSIZE - 1;
58    int last = index;
59
60    while (index != 0)
61    {
62        last = index;
63        index = StaticLinkList[index].cur;
64    }
65
66    int k = MallocNodeSSL(); //獲取空閑位置下標
67    if (k)
68    {
69        StaticLinkList[k].data = AddData; //存入數據
70        StaticLinkList[k].cur = 0;   //末尾指向0
71        StaticLinkList[last].cur = k;
72        return OK;
73    }
74
75    return ERROR;
76
77}
78//在List中第i個節點之前插入新的節點
79template <typename DATATYPE>
80status CStaticLinkList<DATATYPE>::InsertNodeList(DATATYPE InsertData, int index)//指定位置插入
81{
82    int i, GetFree, pos;
83    pos = MAXSIZE - 1;//最后節點下標
84    if (index < 1 || index > GetLengthList() || IsFullList())
85    {
86        return ERROR; //位置異常處理
87    }
88
89    GetFree = MallocNodeSSL();
90    if (GetFree)
91    {
92        StaticLinkList[GetFree].data = InsertData;
93        for (i = 0; i < index - 1; i++)
94        {
95            pos = StaticLinkList[pos].cur; //定位
96        }
97        StaticLinkList[GetFree].cur = StaticLinkList[pos].cur;
98        StaticLinkList[pos].cur = GetFree; //插入
99
100        int q = StaticLinkList[MAXSIZE - 1].cur;
101        if (q == 0//靜態表為空
102        {
103            StaticLinkList[MAXSIZE - 1].cur = 1;
104        }
105        return OK;
106    }
107    return ERROR;
108}
109
110//判斷是否為空
111template <typename DATATYPE>
112status CStaticLinkList<DATATYPE>::IsEmptyList()
113{
114    if (StaticLinkList[MAXSIZE-1].cur == 0)
115    {
116        return YES; 
117    }
118
119    return NO;
120}
121//判斷靜態表是否滿了
122template <typename DATATYPE>
123status CStaticLinkList<DATATYPE>::IsFullList()
124{
125    if (GetLengthList() == MAXSIZE - 2//因為首位不存數據,因此pass掉
126    {
127        return YES;
128    }
129    return NO;
130}
131template <typename DATATYPE>
132int CStaticLinkList<DATATYPE>::GetLengthList() //獲取靜態表的長度
133{
134    int iCount = 0;
135    int k = MAXSIZE - 1;
136    while (StaticLinkList[k].cur != 0)
137    {
138        iCount++;
139        k = StaticLinkList[k].cur;
140    }
141
142    return iCount;
143}
144template <typename DATATYPE>
145status CStaticLinkList<DATATYPE>::DeleteNodeList(DATATYPE *DelData, int index)//指定位置刪除
146{
147    int i, pos, k;
148    pos = MAXSIZE - 1;//最后節點下標
149    if (index < 1 || index > GetLengthList() || IsEmptyList())
150    {
151        return ERROR; //位置異常處理
152    }
153    for (i = 0; i < index - 1; i++)
154    {
155        pos = StaticLinkList[pos].cur; //定位到被刪除節點的前一個節點
156    }
157    k = StaticLinkList[pos].cur; 
158    *DelData = StaticLinkList[k].data; //獲取數據
159    StaticLinkList[pos].cur = StaticLinkList[k].cur;//讓前一個節點直接指向后一個節點.把夾在中間的踢掉
160    FreeNodeSSL(k); //釋放空間
161
162    return OK;
163}
164//搜索數據為sData的節點,返回其在靜態表中的第i個位置,0表示沒找到
165template <typename DATATYPE>
166int CStaticLinkList<DATATYPE>::SearchList(DATATYPE sData)
167{
168    int pos = StaticLinkList[MAXSIZE-1].cur;
169    int iCount = 1;
170    while (pos != 0)
171    {
172        if (StaticLinkList[pos].data == sData) //找到數據
173        {
174            return iCount;
175        }
176        pos = StaticLinkList[pos].cur; //循環遍歷
177        iCount++;
178    }
179
180    return 0;
181}
182template <typename DATATYPE>
183status CStaticLinkList<DATATYPE>::GetIndexList(DATATYPE *gData, int index)//獲取第index個節點數據
184{
185    int i, pos;
186    pos = MAXSIZE - 1;//最后節點下標
187    if (index < 1 || index > GetLengthList() || IsEmptyList())
188    {
189        return ERROR; //位置異常處理
190    }
191    for (i = 0; i < index; i++)
192    {
193        pos = StaticLinkList[pos].cur; //定位到第index個節點
194    }
195    *gData = StaticLinkList[pos].data;
196
197    return OK;
198}
199template <typename DATATYPE>
200status  CStaticLinkList<DATATYPE>::ClearList() //清空靜態表
201{
202    InitList();//再初始化一次就是清空了
203    return  OK;
204}
205template <typename DATATYPE>
206void  CStaticLinkList<DATATYPE>::PrintList()
207{
208    int pos = StaticLinkList[MAXSIZE - 1].cur;
209    if (pos == 0)
210    {
211        cout << "===========靜態鏈表為空,打印雞毛!!!===========" << endl;
212        return;
213    }
214    cout << setiosflags(ios::left);
215    cout << setw(10) << "索引" << setw(10) << "下標" << setw(10) << "data" << setw(10) << "cur" << endl;
216    int iCount = 1;
217    while (pos != 0)
218    {
219        cout << setw(10) << iCount << setw(10) << pos << setw(10) << StaticLinkList[pos].data << setw(10) << StaticLinkList[pos].cur << endl;
220        pos = StaticLinkList[pos].cur; //循環遍歷
221        iCount++;
222    }
223}

StaticLinkListTest.cpp測試代碼

 1#include <iostream>
2#include <iomanip>
3#include "StaticLinkList.h"
4#include "StaticLinkList.cpp"
5using namespace std;
6
7int main()
8
{
9    char get;
10    CStaticLinkList<char> *p = new CStaticLinkList<char>;
11    p->PrintList();
12
13    p->BackAddList('a'); //pass
14    p->BackAddList('b');
15    p->BackAddList('c');
16    p->BackAddList('d');
17    p->BackAddList('e');
18
19    //p->ClearList();      //pass
20
21    p->PrintList();
22
23    p->DeleteNodeList(&get, 2);  //pass
24    cout << "get = " << get << endl;
25
26    p->DeleteNodeList(&get, 2);
27    cout << "get = " << get << endl;
28
29    p->PrintList();
30    p->BackAddList('f');
31
32    p->PrintList();
33    cout << "length = " << p->GetLengthList() << endl;//pass
34
35    p->GetIndexList(&get, 3);  //pass
36    cout << "get = " << get << endl
37
38    p->InsertNodeList('h'2);
39    p->InsertNodeList('i'3);
40
41    p->PrintList();
42    cout << "length = " << p->GetLengthList() << endl;//pass
43
44    cout << "search_pos = " << p->SearchList('q') << endl;
45    cout << "search_pos = " << p->SearchList('h') << endl;
46    cout << "search_pos = " << p->SearchList('i') << endl;
47
48    delete p;
49
50    return 0;
51}

運行結果

運行結果運行結果

代碼未經過嚴謹測試,如果有錯,歡迎大家指正和交流啊.

這次就先到這里吧。更多精彩內容,請期待下回分解。


免責聲明!

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



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