在這里給出數組實現單鏈表和雙鏈表以及指針實現單鏈表和雙鏈表的例子,為以后更為復雜的數據結構實現打基礎。
首先介紹一下使用數組來實現鏈表的原理
int node[maxn]; int cur=0; int Next[maxn]; int tot=0;
node數組是用來保存所有的節點的取值的,這里面的節點是程序生成的流水節點,其真正有沒有出現在鏈表中是沒有任何關系的
cur用來指示當前在node數組中的哪一個位置,是一個位置變量
Next數組用來存node數組中下標位置的節點所連接的下一個元素在node數組中的下標,是鏈表的核心
tot用來記錄當前鏈表中有多少個節點
先是單鏈表
接下來我們給出其中最主要的函數的定義,insert_back函數
void insert_back(int a,int s) { cur++; node[cur]=s; Next[cur]=Next[a]; Next[a]=cur; }
這個函數的用途是在鏈表a位置的元素后面插入一個新的值為s的節點
首先第一步是把新節點賦值之后加入到node數組的尾部
接下來要做的就是插入了,讓新節點的下一個元素指向a節點之前指向的元素
然后讓a節點的下一個元素指向新節點
下面給出單鏈表數組實現的完整程序
1 #include<iostream> 2 using namespace std; 3 const int maxn=1005; 4 int n; 5 int node[maxn]; 6 int cur=0; 7 int Next[maxn]; 8 int tot=0; 9 void insert(int a,int b,int s) 10 { 11 cur++; 12 node[cur]=s; 13 Next[a]=cur; 14 Next[cur]=b; 15 } 16 void insert_back(int a,int s) 17 { 18 cur++; 19 node[cur]=s; 20 Next[cur]=Next[a]; 21 Next[a]=cur; 22 } 23 void insert_front(int b,int s) 24 { 25 cur++; 26 node[cur]=s; 27 Next[cur]=b; 28 int a; 29 for(int i=1;i<=cur;i++) 30 { 31 if(Next[i]==b) 32 { 33 a=i; 34 break; 35 } 36 } 37 Next[a]=cur; 38 } 39 void _delete(int a,int b) 40 { 41 Next[a]=b; 42 } 43 void delete_back(int a) 44 { 45 Next[a]=Next[Next[a]]; 46 } 47 void delete_front(int b) 48 { 49 int s; 50 for(int i=1;i<=cur;i++) 51 { 52 if(Next[i]==b) 53 { 54 s=i; 55 break; 56 } 57 } 58 int a; 59 for(int i=1;i<=cur;i++) 60 { 61 if(Next[i]==s) 62 { 63 a=i; 64 break; 65 } 66 } 67 Next[a]=b; 68 } 69 int main() 70 { 71 cin>>n; 72 int tmp; 73 cin>>tmp; 74 insert_back(0,tmp); 75 tot++; 76 for(int i=1;i<n;i++) 77 { 78 cin>>tmp; 79 insert_back(i,tmp); 80 tot++; 81 } 82 tmp=Next[0]; 83 while(tmp) 84 { 85 cout<<node[tmp]<<" "; 86 tmp=Next[tmp]; 87 } 88 return 0; 89 }
然后我們介紹雙鏈表的數組實現
int node[maxn]; int Prev[maxn]; int Next[maxn]; int cur; int tot=0;
在原來的基礎上新加入了一個數組,用來表示下標位置節點的前一個節點在node數組中的下標
然后我們還是以insert_back函數為例子
void insert_back(int a,int s) { cur++; node[cur]=s; Prev[Next[a]]=cur; Next[cur]=Next[a]; Prev[cur]=a; Next[a]=cur; }
首先將新節點放入node數組中
讓a節點的下一個節點的前驅節點指向新節點
讓a節點的下一個節點成為新節點的后繼
讓新節點的前驅節點指向a節點
讓a節點的后繼節點指向新節點
下面給出完整的雙鏈表的數組實現程序
1 #include<iostream> 2 using namespace std; 3 const int maxn=1005; 4 int n; 5 int node[maxn]; 6 int Prev[maxn]; 7 int Next[maxn]; 8 int cur; 9 int tot=0; 10 void insert(int a,int b,int s) 11 { 12 cur++; 13 node[cur]=s; 14 Next[a]=cur; 15 Prev[cur]=a; 16 17 Next[cur]=b; 18 Prev[b]=cur; 19 } 20 void insert_back(int a,int s) 21 { 22 cur++; 23 node[cur]=s; 24 Prev[Next[a]]=cur; 25 Next[cur]=Next[a]; 26 27 Prev[cur]=a; 28 Next[a]=cur; 29 } 30 void insert_front(int b,int s) 31 { 32 cur++; 33 node[cur]=s; 34 Next[Prev[b]]=cur; 35 Prev[cur]=Prev[b]; 36 37 Next[cur]=b; 38 Prev[b]=cur; 39 } 40 void _delete(int a,int b) 41 { 42 Prev[b]=a; 43 Next[a]=b; 44 } 45 void delete_back(int a) 46 { 47 Prev[Next[Next[a]]]=a; 48 Next[a]=Next[Next[a]]; 49 } 50 void delete_front(int b) 51 { 52 Next[Prev[Prev[b]]]=b; 53 Prev[b]=Prev[Prev[b]]; 54 } 55 int main() 56 { 57 cin>>n; 58 int tmp; 59 cin>>tmp; 60 insert_back(0,tmp); 61 tot++; 62 for(int i=1;i<n;i++) 63 { 64 cin>>tmp; 65 insert_back(i,tmp); 66 tot++; 67 } 68 tmp=Next[0]; 69 while(tmp) 70 { 71 cout<<node[tmp]<<" "; 72 tmp=Next[tmp]; 73 } 74 return 0; 75 }
之后我們要介紹的是鏈表的指針實現
在程序設計競賽中不建議使用這種方式,因為在邊界處理時往往會訪問無效內存
程序競賽中的鏈表,應統一使用數組形式,而對於樹形結構,具體問題具體分析,怎么方便怎么來
首先是使用指針實現鏈表的一些注意項
int n; struct Node { int Data; Node *next; }; Node *head,*rear;
這里節點被封裝成了結構體看起來舒服一些
next里存的是下一個節點的地址
head永遠指向鏈表中的第一個元素,這樣方便進行操作
rear是當前的操作項,相當於位置變量
然后還是以insert_back函數為例
void insert_back(Node* a,int s) { Node *tmp=new Node(); tmp->Data=s; tmp->next=a->next; a->next=tmp; }
這里的邏輯和之前的數組實現是完全一致的
下面給出單鏈表的指針實現的完整代碼
1 #include<iostream> 2 using namespace std; 3 int n; 4 struct Node 5 { 6 int Data; 7 Node *next; 8 }; 9 Node *head,*rear; 10 void insert(Node* a,Node* b,int s) 11 { 12 Node *tmp=new Node(); 13 tmp->Data=s; 14 a->next=tmp; 15 tmp->next=b; 16 } 17 void insert_back(Node* a,int s) 18 { 19 Node *tmp=new Node(); 20 tmp->Data=s; 21 tmp->next=a->next; 22 a->next=tmp; 23 } 24 void insert_front(Node* b,int s) 25 { 26 Node *tmp=new Node(); 27 tmp->next=b; 28 Node *a=head; 29 while(a!=NULL) 30 { 31 if(a->next==b) 32 break; 33 a=a->next; 34 } 35 a->next=tmp; 36 } 37 void _delete(Node* a,Node* b) 38 { 39 delete a->next; 40 a->next=b; 41 } 42 void delete_back(Node* a) 43 { 44 Node *tmp=a->next; 45 a->next=a->next->next; 46 delete tmp; 47 } 48 void delete_front(Node* b) 49 { 50 Node *tmp=head; 51 while(tmp!=NULL) 52 { 53 if(tmp->next==b) 54 break; 55 tmp=tmp->next; 56 } 57 Node *a=head; 58 while(a!=NULL) 59 { 60 if(a->next==tmp) 61 break; 62 a=a->next; 63 } 64 a->next=b; 65 delete tmp; 66 } 67 int main() 68 { 69 cin>>n; 70 head=new Node(); 71 int tmp; 72 cin>>tmp; 73 rear=new Node(); 74 rear->Data=tmp; 75 head->next=rear; 76 for(int i=1;i<n;i++) 77 { 78 cin>>tmp; 79 insert_back(rear,tmp); 80 rear=rear->next; 81 } 82 rear=head->next; 83 while(rear!=NULL) 84 { 85 cout<<rear->Data<<" "; 86 rear=rear->next; 87 } 88 return 0; 89 }
接下來我們介紹雙向鏈表的指針實現
首先還是給出定義項
int n; struct Node { int Data; Node *prev,*next; };
區別就是增加了一個prev用來存前驅節點的地址
然后我們給出insert_back函數的定義
void insert_back(Node* a,int s) { Node *tmp=new Node(); tmp->Data=s; if(a->next!=NULL) a->next->prev=tmp; tmp->next=a->next; tmp->prev=a; a->next=tmp; }
這里的邏輯和之前數組實現基本一致,但是要注意一點那就是一定要考慮好邊界情況,在這里就是往鏈表尾部插入的情況
如果直接是a->next->prev,如果a->next為空,就是訪問無效內存,直接會運行錯誤
所以要加入一個特判
不只在這個地方,在其他的地方也可能出現類似的情況,所以除非有必要,建議不要使用指針形式的鏈表
下面給出雙向鏈表的指針實現的完整代碼
1 #include<iostream> 2 using namespace std; 3 int n; 4 struct Node 5 { 6 int Data; 7 Node *prev,*next; 8 }; 9 Node *head,*rear; 10 void insert(Node* a,Node* b,int s) 11 { 12 Node *tmp=new Node(); 13 tmp->Data=s; 14 15 a->next=tmp; 16 tmp->prev=a; 17 18 tmp->next=b; 19 b->prev=tmp; 20 } 21 void insert_back(Node* a,int s) 22 { 23 Node *tmp=new Node(); 24 tmp->Data=s; 25 26 if(a->next!=NULL) 27 a->next->prev=tmp; 28 tmp->next=a->next; 29 30 tmp->prev=a; 31 a->next=tmp; 32 } 33 void insert_front(Node* b,int s) 34 { 35 Node *tmp=new Node(); 36 tmp->next=b; 37 38 b->prev->next=tmp; 39 tmp->prev=b->prev; 40 41 tmp->next=b; 42 b->prev=tmp; 43 } 44 void _delete(Node* a,Node* b) 45 { 46 Node *tmp=a->next; 47 a->next=b; 48 b->prev=a; 49 50 delete tmp; 51 } 52 void delete_back(Node* a) 53 { 54 Node *tmp=a->next; 55 56 tmp->next->prev=a; 57 a->next=tmp->next; 58 59 delete tmp; 60 } 61 void delete_front(Node* b) 62 { 63 Node *tmp=b->prev; 64 65 tmp->prev->next=b; 66 b->prev=tmp->prev; 67 68 delete tmp; 69 } 70 int main() 71 { 72 cin>>n; 73 head=new Node(); 74 int tmp; 75 cin>>tmp; 76 rear=new Node(); 77 rear->Data=tmp; 78 head->next=rear; 79 rear->prev=head; 80 for(int i=1;i<n;i++) 81 { 82 cin>>tmp; 83 insert_back(rear,tmp); 84 rear=rear->next; 85 } 86 rear=head->next; 87 while(rear!=NULL) 88 { 89 cout<<rear->Data<<" "; 90 rear=rear->next; 91 } 92 return 0; 93 }
所有的程序只測試了一個函數,別的函數實現僅供參考,如有錯誤歡迎讀者指正。