單鏈表學習:參考《大話數據結構》數組
涉及到單鏈表的基本操做有以下:數據結構
int initList(linkList *); //初始化一個單鏈表,具備頭指針,頭結點,頭結點->next=NULL;
int createListHead(linkList *, int n); //頭插法建立一個鏈表,鏈表長度爲n;
int createListTail(linkList *, int n); //尾插法建立一個鏈表,鏈表長度爲n;
int getlength(linkList *); //獲取單鏈表的長度;
int printList(linkList *); //打印整個鏈表;
int getElem(linkList *,int i,ElemType *); //獲取鏈表中第i個位置處節點的數據元素;
int insertList(linkList *, int i, ElemType data); //在鏈表的指定位置(i節點)插入一個節點,i的範圍爲1~length(鏈表總長度);
int insertListTail(linkList *, ElemType data); //給鏈表追加一個節點,在最末尾處增長;
int deleteList(linkList *, int i, ElemType *data); //刪除指定位置(i節點)處的節點,i的範圍爲1~length(鏈表總長度);
int clearList(linkList *); //刪除整個鏈表,使頭結點->next=NULL;函數
(一)ADT:學習
1 typedef int ElemType; 2 typedef struct Node { 3 ElemType data; 4 struct Node * next; 5 }Node; 6 typedef struct Node* linkList;
(二)初始化:int initList(linkList *L)spa
1 int initList(linkList *L) 2 { 3 (*L) = (linkList)malloc(sizeof(Node)); 4 (*L)->next = NULL; 5 printf("鏈表初始化成功\n"); 6 return 1; 7 }
初始化一個指向頭節點的指針,使頭指針->next=NULL,頭指針->data不作處理; 指針
(三)建立一個單鏈表code
1 int createListHead(linkList *L,int n) { 2 linkList p; 3 int i = 0; 4 srand((int)time(0)); 5 for (i = 0; i < n; i++) 6 { 7 p= (linkList)malloc(sizeof(Node)); 8 p->data = rand() % 100; 9 printf("testing:Node[%d]=%d\n",i+1,p->data); 10 p->next = (*L)->next; 11 (*L)->next = p; 12 } 13 printf("鏈表(頭插法)建立成功\n"); 14 return 1; 15 }
說明:blog
一、圖中的head表示頭指針,而在建立單鏈表中的入參phead是指向指針的指針;即*phead等同於head,*head指向頭節點;內存
二、初始化和建立整表的函數中,爲何入參是linkList *類型的參數呢,爲何不是Node *類型的;以前個人理解是可使用Node*類型的入參,這樣聲明一個Node *head,這樣在建立整表的函數中能夠直接createList(head,10),直接傳入頭指針,可是嘗試過之後,會在經過頭指針訪問各節點數據的時候,彈出錯誤窗口,緣由還不太清楚;作用域
3(補充)在看《C和指針》258的時候,看到了這麼一句話,好像能夠解釋爲何須要傳入鏈表的基本操做函數中的入參是一個指針類型的變量;
「i='a';*pi='a';**ppi='a'; //這三條語句具備一樣的效果;i-整型變量,pi-指向i的指針,ppi-指向pi指針的指針;
在一條簡單的對i賦值的語句就能夠完成任務的狀況下,爲何還要使用更爲複雜的涉及間接訪問的方法呢?這是由於簡單賦值並不老是可行,例如鏈表的插入。在那些函數中,咱們沒法使用簡單賦值,由於變量名在函數的做用域內部是未知的。函數所擁有的只是一個指向須要修改的內存位置的指針,因此要對該指針進行間接訪問操做以訪問須要修改的變量。
」
int createListTail(linkList *L, int n) { linkList p, temp; temp = (*L); int i; srand((int)time(0)); for (i = 0; i < n;i++) { p = (linkList)malloc(sizeof(Node)); p->data = rand() % 100; printf("testing:Node[%d]=%d\n", i + 1, p->data); p->next = NULL; temp->next = p; temp = p; } printf("鏈表(尾插法)建立成功\n"); return 1; }
(四)獲取鏈表的長度
1 int getlength(linkList *L) { 2 linkList p; 3 int length=0; 4 p = (*L)->next;//p指向第一個節點; 5 while (p) { 6 length++; 7 p = p->next; 8 } 9 return length; 10 }
(五)打印整個鏈表
1 int printList(linkList *L) { 2 linkList p; 3 int i = 0; 4 p = (*L)->next;//p指向第一個節點; 5 printf("-----------打印整個鏈表-----------\n"); 6 if (p==NULL) { 7 printf("這是一個空鏈表.\n"); 8 } 9 while (p) { 10 i++; 11 printf("第%d個節點的數據data爲=%d\n",i,p->data); 12 p = p->next; 13 } 14 return 1; 15 }
(六)獲取指定位置處的節點元素;
1 int getElem(linkList *L, int i, ElemType *getdata) { 2 linkList p; 3 p = (*L)->next; 4 if (p == NULL) 5 { 6 printf("鏈表爲空,請建立一個鏈表\n"); 7 *getdata = -1; 8 return 0; 9 } 10 if (i < 1) 11 { 12 printf("您所查詢的節點%d,應該大於0,請從新輸入查詢\n",i); 13 *getdata = -1; 14 return 0; 15 } 16 int j = 1; 17 while (p&&j<i) { 18 j++; 19 p = p->next; 20 } 21 if (p == NULL) 22 { 23 printf("您所查詢的節點%d,已經超出了數組的長度\n",i); 24 *getdata = -1; 25 return 0; 26 } 27 *getdata = p->data; 28 printf("查詢成功!\n", i); 29 return 1; 30 }
(七)插入節點;
插入節點分爲兩種,一種是在鏈表的長度範圍內插入節點,第二種是在鏈表的尾部追加一個節點;
假設鏈表的長度爲10,第一種能夠在1-10位置處插入節點,好比在第10個位置插入一個節點,則原先的第10節點變爲了11節點,可是第二種是全部節點位置都不變,在第11個位置追加一個新的節點;
1 int insertList(linkList *L, int i, ElemType data) 2 { 3 linkList p; 4 linkList insNode; 5 p = (*L); 6 int j=0; 7 // 鏈表爲空,在第1個位置插入一個新的節點; 8 if (p ->next == NULL) { 9 printf("鏈表爲空,默認在第一個位置插入一個節點.\n"); 10 insNode = (linkList)malloc(sizeof(Node)); 11 insNode->data = data; 12 insNode->next = p->next; 13 p->next = insNode; 14 printf("節點插入成功.\n"); 15 return 1; 16 } 17 // 鏈表非空的狀況下,能夠在i=1~length的位置插入節點,若是超過了鏈表的長度,就會提示錯誤; 18 // 其實若是在length+1的位置處插入一個新節點,就至關於在尾部追加一個節點,在本函數中會報錯,能夠單獨實現一個函數; 19 while(p && j<i-1) 20 { 21 j++; 22 p = p->next; 23 //printf("j=%d\tp->data=%d\n", j, p->data); 24 } 25 if (p->next==NULL) { 26 printf("您要插入的位置,超過了鏈表的長度 %d,請從新操做!\n",j); 27 return 0; 28 } 29 insNode = (linkList)malloc(sizeof(Node)); 30 insNode->data = data; 31 insNode->next = p->next; 32 p->next = insNode; 33 34 printf("節點插入成功\n"); 35 return 1; 36 }
追加節點;
1 int insertListTail(linkList *L, ElemType data) 2 { 3 linkList temp; 4 linkList p=(*L); 5 while(p) { 6 temp = p; 7 p = p->next; 8 } 9 p = (linkList)malloc(sizeof(Node)); 10 p->data = data; 11 p->next = NULL; 12 temp->next = p; 13 printf("節點插入成功\n"); 14 return 1; 15 }
(八)刪除節點;
1 int deleteList(linkList *L, int i, ElemType *data) 2 { 3 linkList p,pnext; 4 int j = 0; 5 p = (*L); 6 if (p->next == NULL) { 7 printf("鏈表爲空,沒法刪除指定節點.\n"); 8 *data = -1; 9 return 0; 10 } 11 while (p->next && j<i-1) { 12 j++; 13 p = p->next; 14 //printf("j=%d\t p->data=%d\n",j,p->data); 15 }//條件最多定位到最後一個節點; 16 if ( p->next == NULL) { 17 printf("您要刪除的節點,超過了鏈表的長度 %d,請從新操做!\n", j); 18 *data = -1; 19 return 0; 20 } 21 pnext = p->next; 22 p->next = pnext->next; 23 *data = pnext->data; 24 free(pnext); 25 printf("節點刪除成功\n"); 26 return 1; 27 }
(九)刪除這個鏈表;
1 int clearList(linkList *L) { 2 linkList p, temp; 3 p = (*L)->next;//p指向第一個節點 4 while (p) { 5 temp = p; 6 p = p->next; 7 free(temp); 8 } 9 (*L)->next = NULL; 10 printf("整個鏈表已經clear.\n"); 11 return 1; 12 }