單鏈表的c++實現


鏈表同樣是一種線性表,但只是邏輯上的線性,地址空間並不連續,而是靠指針將各個節點連接起來,就像鎖鏈一樣,一環連一環。所以,需要定義一個節點類,用來存儲數據和指向下一個節點的指針。為了簡單,只定義了兩個公有的成員變量。(雙向鏈表則需定義兩個指針,分別指向前驅和后繼)

 1 #ifndef Node_hpp
 2 #define Node_hpp
 3 
 4 class Node
 5 {
 6 public:
 7     int Data;
 8     Node *NEXT;
 9 };
10 
11 #endif /* Node_hpp */

鏈表應該具有線性表的通用功能,所以定義函數為

 1 #ifndef LinkList_hpp
 2 #define LinkList_hpp
 3 #include "Node.hpp"
 4 
 5 class LinkList
 6 {
 7 public:
 8     LinkList();                     //建立鏈表(頭節點)
 9     ~LinkList();                    //銷毀鏈表
10     void ClearList();               //清空鏈表
11     bool ListEmpty();               //鏈表判空
12     int ListLength();               //鏈表長度
13     bool GetElem(int i,Node *pNode);//目標節點內容
14     int LocateElem(Node *pNode);    //目標節點位置
15     bool PriorElem(Node *pCurrentNode,Node *pPreNode);  //目標節點前驅‘
16     bool NextElem(Node *pCurrentNode,Node *pNextNode);  //目標節點后繼
17     bool ListInsert(int i,Node *pNode);                 //插入節點
18     bool ListDelete(int i,Node *pNode);                 //刪除節點
19     bool ListInsertHead(Node *pNode);                   //在鏈表開始處插入
20     bool ListInsertTail(Node *pNode);                   //在鏈表尾部插入
21     void ListTraverse();                                //遍歷鏈表
22 private:
23     Node *_pList;
24     int _iListLen;
25 };
26 
27 #endif /* LinkList_hpp */

在建立鏈表的時候,並不需要規定鏈表的容量,因為有需要加入的內容,只需new一個節點類插入進去就可以了。

所以,構造函數只定義了一個頭節點

1 LinkList::LinkList()
2 {
3     _pList=new Node;
4     _pList->Data=0;
5     _pList->NEXT=NULL;
6     _iListLen=0;
7 }

刪除鏈表需要依次delete所有節點,而清空鏈表同樣要delete掉除頭節點外所有節點。通過while循環,只要當前節點的NEXT指向不為空,就像下一個節點移動,並刪除當前節點。最后,不忘將當前節點置NULL。

 1 void LinkList::ClearList()
 2 {
 3     Node *currentNode=_pList->NEXT;
 4     while(currentNode->NEXT!=NULL)
 5     {
 6         Node *temp=currentNode->NEXT;
 7         delete currentNode;
 8         currentNode=temp;
 9     }
10     currentNode=NULL;
11     _iListLen=0;
12 }

銷毀鏈表時,只需調用清空函數,最后銷毀頭節點

1 LinkList::~LinkList()
2 {
3     ClearList();
4     delete _pList;
5     _pList=NULL;
6 }

根據頭節點的成員變量_iListLen,可以很容易得到判空函數和長度函數。因為鏈表沒有滿的狀態,所以不需要定義判滿

 1 bool LinkList::ListEmpty()
 2 {
 3     if(_iListLen==0)
 4     {
 5         return true;
 6     }
 7     else
 8     {
 9         return false;
10     }
11 }
12 
13 int LinkList::ListLength()
14 {
15     return _iListLen;
16 }

求目標節點數據和位置有相似的地方,都需要依次遍歷,不同的是求數據的時候要先判斷給的位置是否在規定范圍內,再根據給的位置進行循環,而求位置則是直接從頭遍歷至尾,每次循環都要對比當前節點數據和目標節點數據是否相同(如果遍歷至尾都沒有相同的,則返回-1)

 1 bool LinkList::GetElem(int i,Node *pNode)
 2 {
 3     if(i<0||i>=_iListLen)
 4     {
 5         return false;
 6     }
 7     else
 8     {
 9         Node *currentNodt=_pList;
10         for(int k=0;k<=i;k++)
11         {
12             currentNodt=currentNodt->NEXT;
13         }
14         pNode->Data=currentNodt->Data;
15         return true;
16     }
17 }
18 
19 int LinkList::LocateElem(Node *pNode)
20 {
21     Node *currentNode=_pList;
22     int k=0;
23     while(currentNode->NEXT!=NULL)
24     {
25         currentNode=currentNode->NEXT;
26         if(currentNode->Data==pNode->Data)
27         {
28             return k;
29         }
30         k++;
31     }
32     return -1;
33 }

求前驅和后繼的方式相似,定義兩個相鄰節點,遍歷的同時移動,並與目標節點數據進行對比,如果求前驅,則用后面的節點對比,如果求后繼,則用前面的節點對比

 1 bool LinkList::PriorElem(Node *pCurrentNode,Node *pPreNode)
 2 {
 3     Node *currentNode=_pList;
 4     Node *currentNodeBefore=NULL;
 5     while(currentNode->NEXT!=NULL)
 6     {
 7         currentNodeBefore=currentNode;
 8         currentNode=currentNode->NEXT;
 9         if(currentNode->Data==pCurrentNode->Data)
10         {
11             pPreNode->Data=currentNodeBefore->Data;
12             return true;
13         }
14     }
15     return false;
16 }
17 
18 bool LinkList::NextElem(Node *pCurrentNode,Node *pNextNode)
19 {
20     Node *currentNode=_pList;
21     Node *currentNodeBefore=NULL;
22     while(currentNode->NEXT!=NULL)
23     {
24         currentNodeBefore=currentNode;
25         currentNode=currentNode->NEXT;
26         if(currentNodeBefore->Data==pCurrentNode->Data)
27         {
28             pNextNode->Data=currentNode->Data;
29             return true;
30         }
31     }
32     return false;
33 }

插入與刪除與根據位置求數據類似,需要先判斷位置是否合法,再進行遍歷。因為除頭節點外,所有節點都只能由前驅節點的指針得到,所以先賦值插入節點的后繼節點,再將插入節點賦值給前驅節點的后繼。刪除則只需要將目標節點的后繼節點賦值給前驅節點的NEXT指針。

 1 bool LinkList::ListInsert(int i,Node *pNode)
 2 {
 3     if(i<0||i>=_iListLen)
 4     {
 5         return false;
 6     }
 7     else
 8     {
 9         Node *currentNode=_pList;
10         for(int k=0;k<i;k++)
11         {
12             currentNode=currentNode->NEXT;
13         }
14         Node *newNode=new Node;
15         newNode->Data=pNode->Data;
16         newNode->NEXT=currentNode->NEXT;
17         currentNode->NEXT=newNode;
18         _iListLen++;
19         return true;
20     }
21 }
22 
23 bool LinkList::ListDelete(int i,Node *pNode)
24 {
25     if(ListEmpty())
26     {
27         return false;
28     }
29     else
30     {
31         if(i<0||i>=_iListLen)
32         {
33             return false;
34         }
35         else
36         {
37             Node *currentNode=_pList;
38             Node *currentNodeBefore=NULL;
39             for(int k=0;k<=i;k++)
40             {
41                 currentNodeBefore=currentNode;
42                 currentNode=currentNode->NEXT;
43             }
44             currentNodeBefore->NEXT=currentNode->NEXT;
45             pNode->Data=currentNode->Data;
46             _iListLen--;
47             
48             delete currentNode;
49             currentNode=NULL;
50             return false;
51         }
52     }
53 }

在鏈表的頭尾插入則是插入的特殊情況,一個是不需遍歷,一個是需遍歷所有

 1 bool LinkList::ListInsertHead(Node *pNode)
 2 {
 3     Node *temp=_pList->NEXT;
 4     Node *newNode=new Node;
 5     if(newNode==NULL)
 6     {
 7         return false;
 8     }
 9     else
10     {
11         newNode->Data=pNode->Data;
12         newNode->NEXT=temp;
13         _pList->NEXT=newNode;
14         _iListLen++;
15         return true;
16     }
17 }
18 
19 bool LinkList::ListInsertTail(Node *pNode)
20 {
21     Node *currentNode=_pList;
22     while(currentNode->NEXT!=NULL)
23     {
24         currentNode=currentNode->NEXT;
25     }
26     Node *newNode=new Node;
27     if(newNode==NULL)
28     {
29         return false;
30     }
31     else
32     {
33         newNode->Data=pNode->Data;
34         newNode->NEXT=NULL;
35         currentNode->NEXT=newNode;
36    
37         _iListLen++;
38         return true;
39     }
40 }

遍歷鏈表結尾

 1 void LinkList::ListTraverse()
 2 {
 3     using namespace std;
 4     
 5     cout<<endl;
 6     Node *currentNode=_pList;
 7     while(currentNode->NEXT!=NULL)
 8     {
 9         currentNode=currentNode->NEXT;
10         cout<<currentNode->Data<<endl;
11     }
12     cout<<endl;
13 }

最后,因為涉及到好多循環,不可避免的有許多循環次數的問題,如果分析不清楚,可以通過在主函數中調用檢驗

 1 #include <iostream>
 2 #include "LinkList.hpp"
 3 
 4 int main(int argc, const char * argv[]) {
 5     // insert code here...
 6     using namespace std;
 7     
 8     LinkList *p=new LinkList;
 9     
10     Node *c=new Node;
11     
12     c->Data=3;
13     p->ListInsertHead(c);
14     c->Data=2;
15     p->ListInsertHead(c);
16     c->Data=5;
17     p->ListInsertTail(c);
18     c->Data=4;
19     p->ListInsert(2,c);
20     
21     p->ListTraverse();
22     
23     Node *d=new Node;
24     
25     p->GetElem(3, d);
26     cout<<d->Data<<endl;
27     p->PriorElem(c, d);
28     cout<<c->Data<<endl;
29     cout<<d->Data<<endl;
30     p->NextElem(c, d);
31     cout<<c->Data<<endl;
32     cout<<d->Data<<endl;
33     p->ListDelete(2, d);
34     cout<<d->Data<<endl;
35     
36     p->ListTraverse();
37     
38     delete d;
39     d=NULL;
40     
41     delete c;
42     c=NULL;
43     
44     delete p;
45     p=NULL;
46     
47     return 0;
48 }
49 #include <iostream>
50 #include "LinkList.hpp"
51 
52 int main(int argc, const char * argv[]) {
53     // insert code here...
54     using namespace std;
55     
56     LinkList *p=new LinkList;
57     
58     Node *c=new Node;
59     
60     c->Data=3;
61     p->ListInsertHead(c);
62     c->Data=2;
63     p->ListInsertHead(c);
64     c->Data=5;
65     p->ListInsertTail(c);
66     c->Data=4;
67     p->ListInsert(2,c);
68     
69     p->ListTraverse();
70     
71     Node *d=new Node;
72     
73     p->GetElem(3, d);
74     cout<<d->Data<<endl;
75     p->PriorElem(c, d);
76     cout<<c->Data<<endl;
77     cout<<d->Data<<endl;
78     p->NextElem(c, d);
79     cout<<c->Data<<endl;
80     cout<<d->Data<<endl;
81     p->ListDelete(2, d);
82     cout<<d->Data<<endl;
83     
84     p->ListTraverse();
85     
86     delete d;
87     d=NULL;
88     
89     delete c;
90     c=NULL;
91     
92     delete p;
93     p=NULL;
94     
95     return 0;
96 }

數據結構線性表基礎部分告一段落


免責聲明!

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



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