很早之前學的數據結構,放了很久后,以致對里面的一些操作都有些遺忘,故而再次溫習了一下數據結構,並整理了一點兒筆記,放在這里和大家分享, 我的代碼注釋的已經很詳細了,對於容易出錯的地方我也都有標注,歡迎大家交流。
#include "stdafx.h" #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <time.h> #define OK 1 #define ERROR 0 //#define typedef int Status;//函數返回的狀態值類型 typedef int ElemType; typedef struct Node { ElemType data; struct Node *next; } Node;//定義一個單鏈表存儲結構 typedef struct Node *LinkList;//定義一個線性表,定義的是Node結構體的指針 //創建一個具有n個元素的單鏈線性表,采用頭插法創建,注意:其中已經包含了初始化操作 //初始化鏈表,函數調用完畢后,L會指向一個空的鏈表,即會改變指針的值,所以要用*L //*L表示結構體指針的指針 Status List_Link_Create(LinkList *L,int n)//頭插法 { LinkList p; *L =(LinkList) malloc(sizeof(Node));//產生一個頭結點,並使得*L指向這個頭結點,於是*L便是一個頭指針,頭指針是鏈表的必要元素 if (L == NULL) return ERROR; (*L)->next = NULL;//使得頭指針指向的內容為空,建立一個帶頭結點的單鏈表 printf("請輸出n個隨機生成的數字:"); for (int i = 0; i < n; i++) { p = (LinkList)malloc(sizeof(Node));//生成新節點 p->data = rand() % 100 + 1;//隨機生成100以內的數字 printf("%d", p->data); printf(" ");//字符與字符之間空格 p->next = (*L)->next; (*L)->next = p;//插入到表頭 } printf("\n");//換行 return OK; } Status List_Link_Length(LinkList L)//求出單鏈表的長度 { int j = 0; LinkList p; p = L; while (p != NULL) { p = p->next; j++; } printf("單鏈表當前的長度=%d",j); return j; } //Status List_Link_Ini(LinkList L)//初始化一個線性單鏈表 //{ // L = (LinkList)malloc(sizeof(Node));//產生一個頭結點,並使得L指向這個頭結點,於是L便是一個頭指針,頭指針是鏈表的必要元素 // if (L == NULL) // return ERROR; // L->next = NULL;//使得頭結點的指針域為空 // return OK; //} //銷毀鏈表L,釋放鏈表L申請的內存,使L的值重新變為NULL,所以會改變L的值,得用*L Status List_Link_Destory(LinkList *L) { LinkList p,q; p = (*L)->next; while (p) { q = p->next; free(p); p = q; } (*L)->next = NULL;//頭節點的指針域為空 return OK; } Status List_Link_Insert(LinkList *L, int i, ElemType e)//在L中第i個元素之前插入新的數據元素e { int j; LinkList p, s; p = *L; j = 1; while (p&&j<i)//遍歷尋找第i個節點 { p = p->next; ++j; } if (!p || j > i) return ERROR;//第i個元素不存在 s = (LinkList)malloc(sizeof(Node));//生成一個新節點 s->data = e; s->next = p->next;//將p的后繼節點賦值給s的后繼 p->next = s; printf("插入節點的元素的值為:%d\n", e); return OK;//插入成功 } //刪除L的第i個數據元素,並用e返回其值 //注意這里是*e,而不是e,區別於插入當中的變量e Status List_Link_Delete(LinkList *L, int i, ElemType *e) { int j=1; LinkList p, q; p = *L; while (p->next&&j<i)//遍歷尋找第i個元素 { p = p->next; ++j; } if (!(p->next) || j > i) return ERROR;//第i個元素不存在 q = p->next;//q表示即將被刪除元素的節點 *e = q->data; p->next = q->next;//將q 后繼賦值給p的后繼 free(q);//q被利用完畢后,將q釋放 printf("刪除第%d個節點的元素值為:%d\n", i, *e); return OK; } Status List_Link_GetElem(LinkList L, int i, ElemType *e)//取出單鏈表L中的第i個元素,並通過*e返回 { int j; LinkList p; p = L->next;//找到單鏈表L中第一個節點 j = 1; while (p&&j < i) { p = p->next; ++j; } if (!p || j > i) return ERROR;//第i個元素不存在 *e = p->data;//取出第i個元素的數據域並傳值給*e printf("被取出的元素的值為:"); printf("%d\n", *e); return OK; } int main()//測試函數 { LinkList L1; ElemType f,h; List_Link_Create(&L1, 6); List_Link_GetElem(L1, 3, &f); List_Link_Insert(&L1, 3, 15);//在鏈表的第3個節點之前插入元素15 List_Link_Delete(&L1, 3, &h);//刪除鏈表的第3個節點的元素,並返回給h輸出 return OK; } /*1.對於LinkList L : L是指向定義的node結構體的指針, 可以用->運算符來訪問結構體成員, 即L->elem, 而(*L)就是個Node型的結構體了, 可以用點運算符訪問該結構體成員, 即(*L).elem; 2.對於LinkList *L:L是指向定義的Node結構體指針的指針, 所以(*L)是指向Node結構體的指針, 可以用->運算符來訪問結構體成員, 即(*L)->elem, 當然, (**L)就是Node型結構體了, 所以可以用點運算符來訪問結構體成員, 即(**L).elem; 3.在鏈表操作中, 我們常常要用鏈表變量作物函數的參數, 這時, 用LinkList L還是LinkList *L就很值得考慮深究了, 一個用不好, 函數就會出現邏輯錯誤, 其准則是:如果函數會改變指針L的值, 而你希望函數結束調用后保存L的值, 那你就要用LinkList *L, 這樣, 向函數傳遞的就是指針的地址, 結束調用后, 自然就可以去改變指針的值;而如果函數只會修改指針所指向的內容, 而不會更改指針的值, 那么用LinkList L就行了;*/
下面是我在vs2013中的測試結果:
請輸出n個隨機生成的數字:42 68 35 1 70 25
被取出的元素的值為:1
插入節點的元素的值為:15
刪除第3個節點的元素值為:15
請按任意鍵繼續. . .
