單鏈表,循環鏈表,雙向鏈表(C++實現)


單鏈表:
  一.單鏈表與順序表相比:

   1.順序表可以方便的隨機存取表中的任一節點,速度快;但是在表中插入刪除一個數據時,為了保持其他元素的相對次序不變,平均需要移動一半的元素,效率很低;還有若事先對表長估計不足,過小會形成內存浪費,過大則需要拷貝到一個更大的數組,時間開銷很大。相反,鏈表則適用於插入刪除頻繁,表長估計不定的情形。

   2.順序表邏輯位置和物理位置都連續,而單鏈表中的邏輯位置連續,物理位置非連續。

   二.為什么要帶附加表頭?

    因為不帶附加表頭在插入刪除時要分兩種情況:操作節點在表頭和不在表頭;而帶了附加表頭便可以對所有節點一視同仁。

  1 template<class T>
  2 struct LinkNode{//鏈表節點 
  3     T data;
  4     LinkNode *link;
  5     LinkNode(const T& args,LinkNode<T> *ptr=NULL){
  6         data=args;
  7         link=ptr;
  8     }
  9 };
 10 
 11 template<class T>
 12 class List{//帶附加頭節點的單鏈表 
 13     protected:
 14         LinkNode<T> *first;//鏈表頭指針 
 15     public:
 16         List(){
 17             first=new LinkNode<T>;
 18         }
 19         List(const T& x){
 20             first=new LinkNode<T>(x);
 21         }
 22         List(List<T>& L){
 23             T value;
 24             LinkNode<T> *L_head=L.getHead();
 25             LinkNode<T> *temp=first=new LinkNode<T>;
 26             while(L_head->link!=NULL){
 27                 value=L_head->link->data;
 28                 temp->link=new LinkNode<T>(value);
 29                 L_head=L_head->link;
 30                 temp=temp->link; 
 31             }
 32             temp->link=NULL;
 33         }
 34         ~List(){
 35             makeEmpty();
 36         }
 37         void makeEmpty(){//將鏈表置空 
 38             LinkNode<T> *temp;
 39             while(first->link!=NULL){
 40                 temp=first->link;
 41                 first->link=temp->link;
 42                 delete temp;
 43             }
 44         }
 45         int length()const{
 46             LinkNode<T> *temp=first->link;
 47             int count=0;
 48             while(temp!=NULL){
 49                 temp=temp->link;
 50                 count++;
 51             }
 52             return count;
 53         }
 54         LinkNode<T> *getHead()const{//返回附加頭節點地址 
 55             return first;
 56         }
 57         LinkNode<T> *search(T x,int& i){//搜索數據x的地址和序列號 
 58             LinkNode<T> *current=first->link;
 59             int index=1;
 60             while(current!=NULL){
 61                 if(current->data==x)
 62                     break;
 63                 current=current->link;
 64                 index++;
 65             } 
 66             i=index;
 67             return current;
 68         }
 69         LinkNode<T> *locate(int i){//搜索第i個節點的地址 
 70             if(i<0)
 71                 return NULL;
 72             LinkNode<T> *current=first;
 73             int temp=0;
 74             while(current!=NULL&&temp<i){
 75                 current=current->link;
 76                 temp++;
 77             }
 78             return current;
 79         }
 80         bool getData(int i,T& x){//取出第i個元素的值 
 81             if(i<=0)
 82                 return false;
 83             LinkNode<T> *current=locate(i);
 84             if(current==NULL) return false;
 85             x=current->data;
 86             return true; 
 87         }
 88         void setData(int i,T& x){//修改第i個元素的值 
 89             if(i<=0)
 90                 return;
 91             LinkNode<T> *current=locate(i);
 92             if(current==NULL) return;
 93             current->data=x;
 94         }
 95         bool insert(int i,T& x){//在第i個元素后插入x 
 96             LinkNode<T> *current=locate(i);
 97             if(current==NULL) return false;
 98             LinkNode<T> *newNode=new LinkNode<T>(x);
 99             newNode->link=current->link;
100             current->link=newNode;
101             return true; 
102         }
103         bool remove(int i,T& x){//刪除第i個元素的值 
104             LinkNode<T> *current=locate(i-1);
105             if(current==NULL||current->link==NULL) return false;
106             LinkNode<T> *del=current->link;
107             current->link=del->link;
108             x=del->data;
109             delete del;
110             return true;
111         }
112         bool isEmpty()const{
113             return (first->link==NULL)?true:false;
114         }
115         void inputFront(){//向前插入鏈表法 
116             makeEmpty();
117             LinkNode<T> *newNode;
118             T value; 
119             cin>>value;
120             while(value!=-1){
121                 newNode=new LinkNode<T>(value);
122                 newNode->link=first->link;
123                 first->link=newNode;
124                 cin>>value;
125             } 
126         }
127         void inputRear(){//向后插入鏈表法 
128             makeEmpty();
129             LinkNode<T> *newNode,*last=first;
130             T value;
131             cin>>value;
132             while(value!=-1){
133                 newNode=new LinkNode<T>(value);
134                 last->link=newNode;
135                 last=newNode;
136                 cin>>value;
137             }
138         }
139         void output(){//輸出整個鏈表 
140             LinkNode<T> *current=first->link;
141             while(current!=NULL){
142                 cout<<current->data<<" ";
143                 current=current->link;
144             }
145             cout<<endl;
146         }
147 };

測試代碼如下:

 1 void menu(){
 2     cout<<"1.向前插入建表(-1結束)"<<endl;
 3     cout<<"2.向后插入建表(-1結束)"<<endl;
 4     cout<<"3.輸出鏈表"<<endl;
 5     cout<<"4.搜索元素x所在節點的序號"<<endl;
 6     cout<<"5.取出第i個元素的值"<<endl;
 7     cout<<"6.用x的值修改第i個元素的值"<<endl;
 8     cout<<"7.刪除第i個元素"<<endl;
 9     cout<<"8.在第i個元素后面插入x"<<endl;
10     cout<<"9.退出"<<endl;
11 } 
12 
13 template<class T>
14 void function(int num,List<T> *list){
15     switch(num){
16         int x,i;
17         case 1:
18             list->inputFront();
19             break;
20         case 2:
21             list->inputRear();
22             break;
23         case 3:
24             list->output();
25             break;
26         case 4:
27             cin>>x;
28             list->search(x,i);
29             cout<<i<<endl;
30             break;
31         case 5:
32             cin>>i;
33             list->getData(i,x);
34             cout<<x<<endl;
35             break;
36         case 6:
37             cin>>x>>i;
38             list->setData(i,x);
39             break;
40         case 7:
41             cin>>i;
42             list->remove(i,x);
43             break;
44         case 8:
45             cin>>i>>x;
46             list->insert(i,x);
47             break;
48         default:
49             exit(1);
50     }
51 }
52 int main(int argc, char** argv) {
53     int num;
54     List<int> *list=new List<int>(-1);
55     while(true){
56         menu();
57         cin>>num;
58         function(num,list);
59     }
60     return 0; 
61 }

 

 

其次是循環鏈表:

  代碼我就不放了,就講講要修改的地方:

  1.構造函數。first=new LinkNode<T>;后面接上:first->link=first;目的是讓自身首尾相連。如圖:

  

   2.在判斷循環指針是否到達表尾的條件要從NULL換成first。

   小結:

   循環鏈表的目的是只要知道表中任一一個節點的地址,就能遍歷表中其他任一節點。

最后是雙向鏈表:

  修改:

  1.節點的構造函數。需要增加一個前驅指針。

  2.搜索、插入刪除算法。首先是方向,確定方向后算法和單鏈表差不多,區別在於通過前驅指針還是后續指針訪問節點。其次是插入刪除,講起來比較啰嗦,直接看圖:

  這是插入(中間是插入元素),虛線是原來的情況,實線是插入后的情況,可見一共涉及到4個指針。

  這是刪除(中間是刪除元素)。看上去也是涉及4個指針,實際只動了1和4。

  小結:

  雙向鏈表的目的是為了解決在鏈表中不同方向(前/后)訪問元素的問題。

 

 

 

  

 


免責聲明!

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



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