c資料結構線性表之單鏈表(帶頭結點)基本操作
阿新 • • 發佈:2019-02-04
#include<stdio.h> #include<malloc.h> #define MAXSIZE 10 #define ElemType char #define OK 1 #define ERROR 0 typedef struct Node/*結點型別定義*/ { ElemType data; struct Node *next; }Node,*LinkList;/* LinkList為結構體指標型別*/ //換行函式 void enter(int n) { int i; for(i=0;i<n;i++) { printf("\n"); } } //初始化單鏈表 void init_list(LinkList *H) { *H=(LinkList)malloc(sizeof(Node));//建立頭結點 (*H)->next=NULL; //建立空的單鏈表 } //計算單鏈表的長度 int list_len(LinkList H) { Node *p; int j=0; p=H->next; while(p!=NULL) { p=p->next; j++; } return j; } //用尾插法建立單鏈表 int create_from_tail(LinkList H) { Node *r,*s; char c; int flag=1;//設定標誌位,控制建表結束 r=H;//動態指向當前連結串列尾部,便於尾插入,初值指向頭結點 while(flag) { c=getchar(); if(c!='$') { s=(Node *)malloc(sizeof(Node)); s->data=c; r->next=s; r=s; } else { flag=0; r->next=NULL;//將最後一個結點的next置為空,表示連結串列結束 } } enter(1); return(OK); } //列印連結串列資料 void print_out(LinkList H) { Node *p; p=H->next;//從第一個結點開始 while(p!=NULL) { printf("%c ",p->data); p=p->next; } enter(2); } //按結點查詢 Node *get(LinkList H,int i) { int j; Node *p; p=H;j=0; while(p->next!=NULL&&j<i) { p=p->next; j++; } if(i==j) { return p; } else { return NULL; } } //按元素值查詢 int locate(LinkList H,ElemType key) { Node *p; int j=0; p=H->next;//從第一個結點查詢 while(p!=NULL) { if(p->data!=key) { j++; p=p->next; } else break; } if(p==NULL) { printf("未找到元素!"); return(ERROR); } else { printf("此元素位於第%d個節點",j+1);//打印出元素的結點 return(OK); } } //單鏈表插入操作 int ins_list(LinkList H,int i,ElemType e) { Node *pre,*s; int L; L=list_len(H); if(L>=MAXSIZE) { printf("單鏈表已超過要求的長度,無法插入"); enter(2); return(ERROR); } pre=get(H,i-1);//呼叫get函式,找到第i-1個結點 if(pre==NULL) { printf("插入位置不合理"); enter(2); return(ERROR); } else { s=(Node *)malloc(sizeof(Node));//新建s結點 s->data=e;//將插入資料賦給s的資料域 s->next=pre->next;//完成插入 pre->next=s; printf("插入後的連結串列資料:"); print_out(H);//輸出插入後的連結串列資料 return(OK); } } //單鏈表刪除操作 int del_list(LinkList H,int i, char *e) { Node *pre,*s; pre=get(H,i-1);//呼叫get函式,找到第i-1個結點 if(pre==NULL) { printf("刪除位置不合理"); enter(2); return(ERROR); } else { s=pre->next; pre->next=pre->next->next;//刪除結點 *e=s->data; printf("刪除的元素是:%c",*e); enter(1); printf("刪除後的連結串列:"); print_out(H);//輸出刪除後的結點 free(s);//釋放被刪除的結點 return(OK); } } //主方法 int main() { LinkList H; int a,d,f; char b,c,e='m'; init_list(&H);//初始化 printf("用尾插法建立連結串列,請輸入連結串列資料,以$結束:\n"); create_from_tail(H);//尾插發建表 printf("輸出連結串列資料:\n"); print_out(H);//輸出連結串列 if(list_len(H)>MAXSIZE)//限制連結串列長度在10以內 { printf("單鏈表長度:%d已大於要求長度",list_len(H)); enter(2); return(ERROR); } printf("單鏈表長度:%d",list_len(H)); enter(2); printf("請輸入需查詢的節點:"); scanf("%d",&a); if(get(H,a)==NULL) //按結點查詢 { printf("未找到此節點"); enter(2); return(ERROR); } else printf("查詢到的元素:%c",*get(H,a)); enter(2); printf("請輸入要查詢的元素值:"); getchar(); scanf("%c",&b); locate(H,b);//按值查詢 enter(2); printf("請輸入要插入的位置和元素,[hint:輸入兩個資料之間有逗號]:"); getchar(); scanf("%d,%c",&d,&c); ins_list(H,d,c);//插入 printf("請輸入要刪除的位置:"); getchar(); scanf("%d",&f); del_list(H,f,&e);//刪除 return(OK); }
資料結構中,在單鏈表的開始結點之前附設一個型別相同的結點,稱之為頭結點。頭結點的資料域可以不儲存任何資訊,頭結點的指標域儲存指向開始結點的指標(即第一個元素結點的儲存位置)。
作用
1、防止單鏈表是空的而設的.當連結串列為空的時候,帶頭結點的頭指標就指向頭結點.如果當連結串列為空的時候,單鏈表沒有帶頭結點,那麼它的頭指標就為NULL.
2、是為了方便單鏈表的特殊操作,插入在表頭或者刪除第一個結點.這樣就保持了單鏈表操作的統一性!
3、單鏈表加上頭結點之後,無論單鏈表是否為空,頭指標始終指向頭結點,因此空表和非空表的處理也統一了,方便了單鏈表的操作,也減少了程式的複雜性和出現bug的機會。
4、對單鏈表的多數操作應明確對哪個結點以及該結點的前驅。不帶頭結點的連結串列對首元結點、中間結點分別處理等;而帶頭結點的連結串列因為有頭結點,首元結點、中間結點的操作相同 ,從而減少分支,使演算法變得簡單 ,流程清晰。對單鏈表進行插入、刪除操作時,如果在首元結點之前插入或刪除的是首元結點,不帶頭結點的單鏈表需改變頭指標的值,在C 演算法的函式形參表中頭指標一般使用指標的指標(在C+ +中使用引用 &);而帶頭結點的單鏈表不需改變頭指標的值,函式引數表中頭結點使用指標變數即可。