單鏈表的實現C/C++


單鏈表的實現C/C++

鏈表是線性表的另一種實現方式。與順序表不同,鏈表中邏輯上相鄰的數據元素在物理上未必相鄰,而是通過一個指針指明下一個元素的

物理地址。單鏈表中節點類型的描述如下:

 

1 struct LNode {
2     ElemType data;  //節點數據域
3     LNode* next;    //指向下一個節點的指針
4 };
5 typedef LNode* LinkList;

單鏈表的優點:與順序表相比,單鏈表的優點在於插入和刪除操作:雖然單鏈表的插入和刪除操作與順序表一樣時間復雜度都是O(n),但是對於單鏈表來說,

插入和刪除時的基本操作主要是“比較”(對於按位插入刪除,比較是否到了第i位;對於按值操作,比較值是否相等),而順序表插入和刪除時

的基本操作主要是“移動”。從硬件的角度講,做一次比較運算的時間是遠小於賦值運算的。因此,鏈表的插入和刪除操作要高效得多。

 

單鏈表的缺點:由於單鏈表中邏輯上相鄰的元素在物理上未必相鄰,故不能根據第一個元素的地址立即計算出第i個元素的地址。於是單鏈表不支持隨機訪問。

(所謂隨機訪問是指:根據起始地址加上元素序號就可以立即找到任意一個元素。)要在單鏈表中訪問第i個元素,必須一個一個訪問鏈表中每一個元素直到

第i個。

 

以下代碼實現一個帶頭節點的單鏈表,並嘗試實現一種重要操作:將鏈表反序

  1 /* 帶頭節點的單鏈表
  2 
  3      實現操作:
  4      *1 判空
  5      *2 求表長
  6      *3 按位序查找
  7      *4 按值查找
  8      *5 前插操作
  9      *6 后插操作
 10      *7 按位插入
 11      *8 刪除指定節點
 12      *9 按位刪除
 13      *10 單鏈表的建立-頭插和尾插
 14                                 */
 15 #include <iostream>
 16 #include <cstdio>
 17 using namespace std;
 18 
 19 typedef int ElemType;
 20 typedef struct LNode {
 21     ElemType data;  //節點數據域
 22     LNode* next;    //指向下一個節點的指針
 23 } * LinkList;
 24 
 25 bool Empty(LinkList& L)
 26 {
 27     if( L->next == NULL )
 28         return true;
 29     return false;
 30 }
 31 
 32 //求表的長度
 33 int Length(LinkList L)
 34 {
 35     int j = 0;
 36     LNode* p = L;
 37     //始終讓p指向第j個節點,當p沒有下一個節點時,j就是表的長度
 38     while( p->next != NULL ) {
 39         j++;
 40         p = p->next;
 41     }
 42     return j;
 43 }
 44 
 45 //按位序查找,返回指向第i個節點的指針
 46 //查找失敗時返回的是NULL
 47 LNode* GetElem(LinkList L,int i)
 48 {
 49     if( i < 0 )
 50         return NULL;
 51     int j = 0;
 52     LNode* p = L;
 53     while( j < i && p != NULL ) {
 54         j++;
 55         p = p->next;
 56     }
 57     return p;   //i=0時返回的是頭節點,i值大於表長是返回的是空指針
 58 }
 59 
 60 //按值查找,找到數據域為e的節點,返回其指針
 61 LNode* LocateElem(LinkList L,ElemType e)
 62 {
 63     LNode* p = L->next; //注意不是LNode* p = L :因為指向頭節點,數據域是未知的
 64     while( p != NULL && p->data != e ) {
 65         p = p->next;
 66     }
 67     return p;   //若e不存在,返回空指針
 68 }
 69 
 70 //前插操作:在p節點之前插入元素e
 71 bool InsertPriorNode(LNode* p,ElemType e)
 72 {
 73     if( p == NULL )
 74         return false;
 75 
 76     //偷天換日
 77     LNode* s = new LNode;
 78     s->next = p->next;
 79     p->next = s;
 80     s->data = p->data;
 81     p->data = e;
 82     return true;
 83 }
 84 
 85 //后插操作:在p節點之后插入元素e
 86 bool InsertNextNode(LNode* p,ElemType e)
 87 {
 88     if( p == NULL )
 89         return false;
 90     LNode* s = new LNode;
 91     s->data = e;
 92     s->next = p->next;
 93     p->next = s;
 94     return true;
 95 }
 96 
 97 //按位插入:在單鏈表L的第i個位置插入元素e
 98 bool ListInsert(LinkList& L,int i,ElemType e)
 99 {
100     if( i < 1 )
101         return false;   //位序最小是1
102 
103     //先拿到指向第i-1個節點的指針,然后在他后面插入元素e
104     LNode* p = GetElem(L,i-1);
105     return InsertNextNode(p,e);
106 }
107 
108 //刪除指定節點p
109 bool DeleteNode(LNode* p)
110 {
111     if( p == NULL )
112         return false;
113     //偷天換日
114     LNode* s = p->next;
115     //有bug:當p是最后一個節點時,無法刪除(無法從p->next獲取data)
116     //非要刪除最后一個節點的話,可以傳L頭節點指針進來
117     p->data = s->data;
118     p->next = s->next;
119     delete s;
120 
121     return true;
122 }
123 
124 //按位刪除:刪除單鏈表L的位序為i的元素,並用e返回
125 bool ListDelete(LinkList& L, int i,int& e)
126 {
127     if( i < 1 )
128         return false;
129     LNode* p = GetElem(L,i-1);
130 
131     if( p == NULL ) //沒有第i-1個節點,更沒有第i個節點
132         return false;
133     if( p->next == NULL ) //找到了第i-1個節點,但是沒有第i個節點
134         return false;
135     LNode* t = p->next;
136     e = t->data;
137     p->next = t->next;
138     delete t;
139     return true;
140 }
141 
142 //頭插法建立單鏈表(假設所給數據從鍵盤輸入)
143 LinkList List_HeadInsert(LinkList& L)
144 {
145     //假設元素為int型
146     int x;
147     L = new LNode;
148     L->next = NULL;
149     while( cin >> x ) {
150         InsertNextNode(L,x);
151     }
152     return L;
153 }
154 
155 //尾插法建立單鏈表(假設所給數據從鍵盤輸入)
156 LinkList List_TailInsert(LinkList& L)
157 {
158     //假設元素為int型
159     int x;
160     L = new LNode;
161     L->next = NULL;
162     LNode* r = L;
163     while( cin >> x ) {
164         LNode* s = new LNode;
165         s->data = x;
166         r->next = s;
167         r = s;  //創建過程中不必將尾節點的next置空,因為后面還會有節點
168     }
169     r->next = NULL; //鏈表創建結束,最后一個節點的下一個節點置空
170     return L;
171 }
172 
173 //按順序輸出單鏈表中所有元素
174 void Print(LinkList L)
175 {
176     if( L == NULL )
177         return ;
178     LNode* iterater = L->next;
179     while( iterater != NULL ) {
180         cout << iterater->data << endl;
181         iterater = iterater->next;
182     }
183 }
184 
185 void test1()
186 {
187     //*測試使用a[i]=2*i的100個元素建立鏈表
188     int a[100];
189     for( int i=0; i<100; i++ ) {
190         a[i] = 2*i;
191     }
192     LinkList L = new LNode;
193     L->next = NULL;
194     //使用尾插法將以上數組插入鏈表L
195     LNode* r = L;
196     for( int i=0; i<100; i++ ) {
197 
198         LNode* s = new LNode;
199         s->data = a[i];
200         r->next = s;
201         r = s;
202     }
203     r->next = NULL;
204 
205     //*測試在值為20的元素后插入元素985211
206     LNode* t = LocateElem(L,20);    //按值查找
207     InsertNextNode(t,985211);
208 
209     //*測試刪除位序為15的元素(值應該是26)
210     LNode* tt = GetElem(L,15);      //按位序查找
211     if( tt != NULL ) {
212         DeleteNode(tt);
213     }
214 
215     //*測試按位序刪除位序為100的元素
216     int ttt = 0;
217     if( ListDelete(L,100,ttt) )
218         cout << "按位序刪除成功,刪除的元素是:" << ttt << endl;
219     Print(L);
220     cout << "-------------------------------" << endl;
221 
222 
223     //下面嘗試將L反序 *****重要*****
224     //抓住鏈表中的第一個數據元素,一個一個往后進行頭插,表頭結點指針還是L
225     LNode* it = L->next;
226     L->next = NULL; //*****第一個數據已經抓住了;不加這句會導致表尾自己指向自己(而非指向NULL)
227 
228     //從鏈表的第一個節點開始,一個一個地在將表中所有節點重新插在表頭
229     while( it != NULL ) {
230         LNode* nxt = it->next;
231         it->next = L->next;
232         L->next = it;   //頭插法重構鏈表,即可將鏈表反序
233         it = nxt;
234     }
235     Print(L);
236 
237     //*測試查找不存在的元素返回空指針
238     if( LocateElem(L,999) == NULL ) {
239         cout << endl << "999不存在" << endl;
240     }
241 
242 }
243 
244 //測試頭插法
245 void test2()
246 {
247     LinkList L;
248     List_HeadInsert(L);
249     Print(L);
250 }
251 
252 int main()
253 {
254 //    test1();
255 //    test2();
256     return 0;
257 }

 


免責聲明!

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



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