數據結構——鏈表
阿新 • • 發佈:2019-01-01
ali for 單元 遍歷 next != com 發生 src
頭指針或者尾指針需要改變,並且需要把改變的值帶回到主程序,帶回到調用處需要用的指針的指針;
當尾指針不發生改變,或者即使發生了改變也不希望帶回到主程序當中就用指針;
1 鏈式存儲結構
特點:用一組任意的存儲單元存儲線性表中的數據元素;這組存儲單元可以使連續的也可以是不連續的;每個數據元素除了存儲數據外,還要存儲前驅、後繼元素的地址。
每個元素包括數據域和指針域;存儲數據的部分就是數據域,存儲地址的部分就是指針域;
data | address |
數據域 | 指針域 |
2 單鏈表
n個節點按鏈式存儲結構存儲,每個節點只包含一個指針域;
2.1 線性表的單鏈表存儲結構
typedef int DataType; typedef struct Node { DataType data; struct Node *next; }Node;
2.2 獲取指定位置的元素
typedef int DataType; typedef struct Node { DataType data; struct Node *next; }Node; Node* getptr(Node* head,int pos) { Node *p=head; if(p==NULL || pos==0) { return head; } for(int i=0;p&&i<pos;i++) p=p->next; return p; } void main() { Node *head=NULL; ... Node *p=getptr(head,3); //獲取第3個節點的元素 }
2.3 獲取單鏈表中節點個數
typedef int DataType; typedef struct Node { DataType data; struct Node *next; }Node; int getSize(Node* head) { int size=0; Node *p=head;while(p) //直到p指向的節點地址域為空時,停止循環,返回size { size++; p=p->next; } return size; } void main() { Node *head=NULL; ... int len=getSize(head); //獲取第3個節點的元素 }
2.4 單鏈表插入節點
typedef int DataType; typedef struct Node { DataType data; struct Node *next; }Node; bool insert(Node**head,int position,DataType d) { if(position<0||position>getSize(*head)) return false; Node *node=(Node*)malloc(sizeof(Node)); node->next=NULL; node->next=d; if(position==0) //if中的語句實現插入空鏈表或頭部 { node->next=*head; *head=node; return true; } Node *p=getptr(*head,position-1); //以下5條語句實現插入中間或者尾部 Node *r=p->next; node->next=r; p->next=node; return true; } void main() { Node *head=NULL; ... insert(&head,0,10); //頭部或者空表插入數據10 insert(&head,3,7); //第3個節點插入數據7 }
2.5 單鏈表刪除
bool erase(Node **head,int pos) { if(pos<0 || pos>getSize(*head)) return false; Node *p=*head; if(pos==0) { *head=(*head)->next; free(p); //是否指針p,即刪除p指向的節點 p=NULL; //節點不存在就讓它為空,防止出現意外 return true; } p=getptr(*head,pos-1); Node *q=p->next; p->next=q->next; free(q); q=NULL; return true; } void main() { Node *head=NULL; insert(&head,0,10); insert(&head,0,8); insert(&head,0,3); insert(&head,0,5); erase(&head,0); erase(&head,1); }
2.6 將兩個線性鏈表合並
void union(Node *a,Node *b) { Node *p=*a; if(p->next) p=p->next; p->next=b; } void main() { Node *ahead=NULL; Node *bhead=NULL; insert(&ahead,0,10); insert(&ahead,0,3); insert(&ahead,0,8); insert(&ahead,0,5); insert(&bhead,0,7); insert(&bhead,0,6); insert(&bhead,0,2); insert(&bhead,0,4); union(ahead,bhead); }
2.7 線性鏈表的倒置
void reverse(Node **head) { Node *p=*head; Node *q=p->next; if(q==NULL) return; Node *r=q->next; if(p==*head) //可以不要,最好不要 p->next=NULL; while(true) { q->next=p; if(r==NULL) { *head=q; break; } elase { p=q; q=r; r=r->next; } } } void main() { Node *head=NULL; insert(&head,0,10); insert(&head,0,3); insert(&head,0,8); insert(&head,0,8); reverse(&head); }
2.8 線性鏈表的遍歷
void print(DataType d) { printf("%d\n",d); } void trave(Node *head,void(*fun)(DataType)) { Node *p=head; while(p) { fun(p->data); p=p->next; } } void main() { Node *head=NULL; insert(&head,0,10); insert(&head,0,3); insert(&head,0,8); insert(&head,0,8); trave(head,print); }
3 單循環鏈表
循環鏈表:
將單鏈表中最後一個節點的指針域由空改為指向第一個節點,使整個單鏈表形成一個環;
3.1 線性表的單循環列表存儲結構
typedef int DataType typedef struct Node { DataType data; struct Node *next; }Node;
3.2 獲取單循環鏈表中的節點個數
typedef int DataType typedef struct Node { DataType data; struct Node *next; }Node; int getSize(Node *rear) { int size=0; if(rear) { Node *p=rear->next; while(p!=rear) { size++; p=p->next; } size++; } return size; } void main() { Node *rear=NULL; //定義尾指針指向單鏈表最後一個節點,rear->next會指向頭指針,相當於頭指針 ... int len=getSize(rear); }
3.3 獲取指定位置的元素
typedef int DataType typedef struct Node { DataType data; struct Node *next; }Node; Node *getptr(Node *rear,int pos) { if(rear==NULL) return rear; if(pos<0 || pos>=getSize(rear)) return NULL; Node *p=rear->next; for(int i=0;i<pos;i++) p=p->next; return p; } void main() { Node *rear=NULL; ... Node *p=getptr(rear,2); }
3.4 單循環鏈表插入節點
typedef int DataType typedef struct Node { DataType data; struct Node *next; }Node; bool insert(Node **rear,int position,DataType d) { if(position<0 || position>getSize(*head)) return false; Node *node=(Node*)malloc(sizeof(Node)); node->data=d; node->next=NULL; if(position==0) { if(*rear==NULL) { node->next=node; *rear=node; } else { node->next=(*rear)->next; (*rear)->next=node; } return true; } Node *p=getptr(*head,position-1); Node *r=p->next; node->next-r; p->next=node; if(*rear=p) { *rear=node; } return ture; } void main() { Node *rear=NULL; insert(&rear,0,10); insert(&rear,0,3); insert(&rear,0,8); insert(&rear,1,5); }
3.5 單循環列表的刪除
bool erase(Node **rear,int pos) { if(*rear==NULL || pos<0 || pos>getSize(*head)) return false; Node *p=(*rear)->next; if(pos==0) { (*rear)->next=p->next; free(p); //是否指針p,即刪除p指向的節點 p=NULL; //節點不存在就讓它為空,防止出現意外 return true; } p=getptr(*rear,pos-1); Node *q=p->next; p->next=q->next; if(q==*rear) *rear=p; free(q); q=NULL; return true; } void main() { Node *rear=NULL; insert(&rear,0,10); insert(&rear,0,8); insert(&rear,0,3); insert(&rear,0,5); erase(&rear,0); erase(&rear,1); }
數據結構——鏈表