單連結串列實現
目錄
線性表是資料結構的第一章,而考研和找工作都喜歡考察這方面的內容,因此,我就用C++實現了單連結串列,以及一些常見的演算法題。
本文的具體內容包括:
- 單連結串列的基本操作
- 反向輸出單連結串列
- 找到兩個單連結串列的第一個公共結點
- 對單連結串列進行排序
- 將兩個有序的連結串列合在一起,使之仍然有序
單連結串列的基本操作
不多說,直接上程式碼(注意基本操作中引數L的不同):
///初始化一個單連結串列,申請頭結點
void InitList(LinkList *L){
*L = new LNode;
if(*L==NULL){
cout<<"new error"<<endl;
return;
}
(*L)->next = NULL;
}
///釋放頭結點,將其設為null
void DestroyList(LinkList *L){
LinkList t ;
while((*L)!=NULL){
t = (*L)->next;
delete (*L);
(*L) = t;
}
}
///釋放除頭結點以外的所有空間
void ClearList(LinkList L){
LinkList t,q=L;
L = L->next;
while(L!=NULL){
t = L->next;
delete L;
L = t;
}
q->next = NULL;
}
///獲取連結串列的長度
int Length(LinkList L){
if(L == NULL)
return -1;
int cnt = 0;
L = L->next;
while(L!=NULL){
++cnt;
L=L->next;
}
return cnt;
}
///返回連結串列L中第1個與e相等的元素的位置
int locateElem(LinkList L,int e){
if(L==NULL)
return -1;
int index = 0;
L = L->next;
while(L!=NULL){
if(L->data==e){
return index;
}
++index;
L = L->next;
}
return -1;
}
///獲取連結串列第i個元素的值
bool getElem(LinkList L,int i,LNode &e){
if(L==NULL or i<0)
return false;
int j = 0;
L = L->next;
while(L!=NULL){
if(j==i){
e.data=L->data;
e.next=L->next;
return true;
}
++j;
L = L->next;
}
return false;
}
///在L中第i個位置插入結點e
bool ListInsert(LinkList L,int i,LNode e){
if(L==NULL)
return false;
LinkList p;
p = L;
L = L->next;
int j = 0;
while(p!=NULL){
if(j==i){
LinkList t;
t = new LNode;
t->data = e.data;
t->next = e.next;
p->next = t;
t->next = L;
return true;
}
p = L;
L = L->next;
++j;
}
return false;
}
///刪除第i個元素,並返回該結點
bool ListDelete(LinkList L,int i,LNode &e){
if(L==NULL)
return false;
LinkList p;
int j = 0;
p = L;
L = L->next;
while(L!=NULL){
if(i==j){
e.data = L->data;
e.next = L->next;
p->next = L->next;
delete L;
return true;
}
p = p->next;
L = L->next;
++j;
}
return false;
}
///列印單連結串列L
void PrintList(LinkList L){
if(L==NULL)
return;
L = L->next;
while(L!=NULL){
cout<<L->data<<' ';
L = L->next;
}
cout<<" end"<<endl;
}
測試程式碼:
LinkList L;
InitList(&L);
cout<<"the address of the head node is "<<L<<endl;
LNode e;
e.data = 124;
e.next = NULL;
ListInsert(L,0,e);
e.data = 132;
ListInsert(L,0,e);
e.data = 123;
ListInsert(L,0,e);
PrintList(L);
cout<<"the length of L is "<<Length(L)<<endl;
cout<<"the location of 132 is "<<locateElem(L,132)<<endl;
if(getElem(L,1,e)){
cout<<"the value of location 1 is "<<e.data<<endl;
}
if(ListDelete(L,1,e))
cout<<"the value of deleted element is "<<e.data<<endl;
else
cout<<"delete failed"<<endl;
ClearList(L);
cout<<L<<endl;
DestroyList(&L);
cout<<L<<endl;
執行結果:
反向輸出單連結串列
///從尾到頭反向輸出單連結串列L
///思路:反向輸出很容易就想到棧,
///然後遞迴的本質就是棧,因此可以用
///遞迴來實現,先一層層遞迴到連結串列尾部,
///當指標為NULL時,返回,返回時輸出當前節點的值
void PrintListByReverse(LinkList L){
if(L==NULL)
return;
PrintListByReverse(L->next);
cout<<L->data<<' ';
}
測試程式碼:
LinkList L;
InitList(&L);
LNode e;
e.data = 124;
e.next = NULL;
ListInsert(L,0,e);
e.data = 132;
ListInsert(L,0,e);
e.data = 123;
ListInsert(L,0,e);
e.data = 88;
ListInsert(L,0,e);
e.data = 14;
ListInsert(L,0,e);
e.data = 26;
ListInsert(L,0,e);
cout<<"the origin linklist is:"<<endl;
PrintList(L);
cout<<"print list in reverse:"<<endl;
PrintListByReverse(L->next);
cout<<"end"<<endl;
執行結果:
求兩個單連結串列的公共結點
///找到兩個連結串列的第一個公共結點
/**< 思路:若兩個單連結串列有公共結點,那麼他們的邏輯結構
肯定是Y形而不是X形(因為節點的next域只有一個),因此,
可以先計算兩個連結串列的長度,然後先讓較長的先移動d
(他們的長度差)個節點這樣他們就會同時到達公共結點,
只需比較兩個指標就可以了 */
bool FindCommonNode(LinkList La,LinkList Lb,LNode &e){
if(La==NULL || Lb==NULL)
return false;
int la,lb;///La/Lb 的長度
la = Length(La);
lb = Length(Lb);
int d = la-lb;
int i = 0;
La = La->next;
Lb = Lb->next;
if(d>0){
while(La!=NULL){
if(i==d){
break;
}
++i;
La = La->next;
}
}
else{
d=-d;
while(Lb!=NULL){
if(i==d){
break;
}
++i;
Lb = Lb->next;
}
}
while(La!=NULL && Lb!=NULL){
if(La == Lb){
e.data = La->data;
e.next = La->next;
return true;
}
La = La->next;
Lb = Lb->next;
}
return false;
}
測試程式碼:
LinkList L;
InitList(&L);
LNode e;
e.data = 124;
e.next = NULL;
ListInsert(L,0,e);
e.data = 132;
ListInsert(L,0,e);
LinkList myList;
InitList(&myList);
e.data = 83;
ListInsert(myList,0,e);
e.data = 19;
ListInsert(myList,0,e);
e.data = 46;
ListInsert(myList,0,e);
ConcatList(myList,L);
cout<<"list 1 is:"<<endl;
PrintList(myList);
LinkList hisList;
InitList(&hisList);
e.data = 547;
ListInsert(hisList,0,e);
e.data = 78;
ListInsert(hisList,0,e);
ConcatList(hisList,L);
cout<<"list 2 is:"<<endl;
PrintList(hisList);
if(FindCommonNode(myList,hisList,e))
cout<<"the first common node is "<<e.data<<endl;
執行結果:
單連結串列排序
///對單連結串列進行排序
/**< 可使用插入排序,每次從後面選擇一個結點,
在前面有序的序列選擇一個合適的位置插入 */
void SortList(LinkList L){
if(L==NULL)
return;
LinkList q,r,s,x;
r = L;
x = L;
L=L->next;
bool flag;
while(L!=NULL){
///在前面找到合適的位置插入
s = r;
q = r->next;
flag = false;
while(q!=NULL && q!=L){
///找到第一個比當前結點大的結點
if(q->data > L->data){
flag = true;
x->next = L->next;
L->next = q;
s->next = L;
//PrintList(r);
break;
}
s = s->next;
q = q->next;
}
if(flag!= true)
x=x->next;
L=x->next;
}
}
測試程式碼:
LinkList L;
InitList(&L);
LNode e;
e.data = 124;
e.next = NULL;
ListInsert(L,0,e);
e.data = 132;
ListInsert(L,0,e);
LinkList myList;
InitList(&myList);
e.data = 83;
ListInsert(myList,0,e);
e.data = 19;
ListInsert(myList,0,e);
e.data = 46;
ListInsert(myList,0,e);
ConcatList(myList,L);
cout<<"before sort:"<<endl;
PrintList(myList);
SortList(myList);
cout<<"after sort:"<<endl;
PrintList(myList);
執行結果:
合併有序單連結串列
///合併有序單連結串列La、Lb,放到La裡面去,並且合併後的連結串列仍然有序
void MergeList(LinkList La,LinkList Lb){
LinkList pa = La->next,pb = Lb->next,t;
LNode *r;
La->next = NULL; ///La 作為結果連結串列的指標
t = La;
while(pa != NULL && pb != NULL){
if(pa->data > pb->data){
r = pb->next; ///r 暫存pb的後繼結點
///在La插入
pb->next = La->next;
La->next = pb;
///恢復pb為下一個待比較結點
pb = r;
La = La->next;
}
else{
r = pa->next; ///r 暫存pb的後繼結點
///在La插入
pa->next = La->next;
La->next = pa;
///恢復pb為下一個待比較結點
pa = r;
La = La->next;
}
//PrintList(t);
}
if(pa!=NULL)
La->next = pa;
if(pb!=NULL)
La->next = pb;
delete Lb;
}
測試程式碼:
LNode e;
LinkList List1;
InitList(&List1);
e.data = 24;
ListInsert(List1,0,e);
e.data = 68;
ListInsert(List1,0,e);
e.data = 35;
ListInsert(List1,0,e);
e.data = 123;
ListInsert(List1,0,e);
e.data = 77;
ListInsert(List1,0,e);
e.data = 15;
ListInsert(List1,0,e);
SortList(List1);
LinkList List2;
InitList(&List2);
e.data = 23;
ListInsert(List2,0,e);
e.data = 46;
ListInsert(List2,0,e);
e.data = 98;
ListInsert(List2,0,e);
e.data = 143;
ListInsert(List2,0,e);
e.data = 18;
ListInsert(List2,0,e);
e.data = 85;
ListInsert(List2,0,e);
SortList(List2);
cout<<"list 1 is :"<<endl;
PrintList(List1);
cout<<"list 2 is :"<<endl;
PrintList(List2);
MergeList(List1,List2);
cout<<"after merge:"<<endl;
PrintList(List1);
執行結果:
總結
雖然說單連結串列邏輯比較簡單,但是涉及指標操作,很容易出錯,我建議在紙上畫圖來編寫程式碼,這樣思路比較清晰。
相關文章
- 連結串列-單連結串列實現
- Python實現單連結串列Python
- go 實現單向連結串列Go
- 【資料結構】連結串列(單連結串列實現+詳解+原碼)資料結構
- 單連結串列建立連結串列出現問題
- js實現資料結構--單連結串列JS資料結構
- 單向迴圈連結串列的實現
- 單連結串列實現增刪改查
- Python實現單向連結串列詳解Python
- 連結串列 - 單向連結串列
- 資料結構 - 單連結串列 C++ 實現資料結構C++
- 資料結構和演算法——Go實現單連結串列並且反轉單連結串列資料結構演算法Go
- FreeRTOS連結串列實現
- DS單連結串列--類實現(未完成)
- 資料結構——單連結串列的C++實現資料結構C++
- 資料結構之php實現單向連結串列資料結構PHP
- 單連結串列
- 演算法與資料結構-連結串列((linked-list)-Java實現單向連結串列演算法資料結構Java
- 實現雙向連結串列
- 用JavaScript實現功能齊全的單連結串列JavaScript
- Java實現單向連結串列基本功能Java
- 資料結構實驗之連結串列五:單連結串列的拆分資料結構
- 簡單介紹python中的單向連結串列實現Python
- 資料結構-單連結串列、雙連結串列資料結構
- 用c語言實現資料結構——單連結串列C語言資料結構
- 資料結構-2.單向連結串列的實現資料結構
- 資料結構--單連結串列(通過陣列實現)資料結構陣列
- 資料結構——單連結串列介面實現(C語言)資料結構C語言
- 單雙連結串列
- c語言單向連結串列逆轉實現方法C語言
- 單連結串列實現原理以及具體程式碼(java)Java
- TypeScript 實現連結串列反轉TypeScript
- 連結串列找環(python實現)Python
- Go實現雙向連結串列Go
- java實現連結串列反轉Java
- java實現雙向連結串列Java
- golang 實現連結串列爽不爽?Golang
- 019 透過連結串列學Rust之雙連結串列實現PeekRust
- 019 通過連結串列學Rust之雙連結串列實現PeekRust