Github:(https://github.com/FlameCharmander/DataStructure)
本來是在和順序表裏放一起寫。但是考慮簡潔的話,就這樣寫了。
直接上鍊表的代碼了。
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
typedef int BOOL;
#define TRUE 1
#define FALSE 0
typedef struct LinkNode{
ElemType data;
struct LinkNode* next;
}LinkList, Node;
void InitList(LinkList *list); //初始化鏈表
BOOL Insert(LinkList *list, ElemType e, int pos); //將元素插入
BOOL Delete(LinkList *list, ElemType e); //將指定元素刪除
BOOL IsEmtpy(LinkList *list); //判斷鏈表是否爲空
int main()
{
LinkList list;
InitList(&list);
printf("%d\n", IsEmtpy(&list));
Insert(&list, 'a', 1);
Insert(&list, 'b', 2);
Insert(&list, 'c', 1);
Delete(&list, 'a');
Node *p = list.next;
while (p != NULL) {
printf("%c ", p->data);
p = p->next;
}
printf("\n%d\n", IsEmtpy(&list));
Delete(&list, 'b');
Delete(&list, 'c');
printf("%d\n", IsEmtpy(&list));
return 0;
}
void InitList(LinkList *list){
list->next = NULL; //設置一個頭結點
}
BOOL Insert(LinkList *list, ElemType e, int pos){
int i;
Node* pre = list;
for (i = 1; i < pos; ++i){
pre = pre->next;
}
Node *node = (Node *)malloc(sizeof(Node));
node->data = e;
node->next = pre->next;
pre->next = node;
return TRUE;
}
BOOL Delete(LinkList *list, ElemType e){
Node* pre = list;
while (pre->next != NULL) {
if (pre->next->data == e){
Node* q = pre->next; //臨時存儲
pre->next = pre->next->next;
free(q);
return TRUE;
} else {
pre = pre->next;
}
}
return FALSE;
}
BOOL IsEmtpy(LinkList *list){
if (list->next == NULL) {
return TRUE;
} else {
return FALSE;
}
}
老規矩,要對代碼做一個解釋了,可以再開窗口對照着看。
Line 1~2 是導入頭文件
Line 4 Typedef是給用來爲複雜的聲明定義簡單的別名,所以這裏我這裏設置ElemType char,如果到時鏈表的元素類型不是char,比如只要int,只需typedef int ElemType。
Line 5~7 由於C語言沒有布爾類型,所以這裏用了int代替,1代表True,0代表False
Line 9~12 這是鏈表的數據結構,如果不太熟的話,去看看理論部分吧。
Line 14~17 函數的聲明,如果函數寫在main函數下面,需要在這裏做個定義
Line 19~38 這裏是main函數,就是將所寫的操作給測試一下,看有沒有出錯
Line 40~42 這裏默認鏈表是有頭結點的,這樣插入和刪除等會方便很多,如果你不知道頭結點是什麼,我簡單說下,頭結點就是一個沒有值的結點,下面會講爲什麼需要投結點。
Line 44~55 這就是我們的插入操作了。1<=pos<=n。
Line 46 pre代表是前一個結點的意思。我畫了張圖,是鏈表插入了元素a,b之後的圖。
第一個沒有值的結點就是頭結點了,現在我們要插入c到1的位置,也就是a的前面,那麼我們需要a之前的結點(現在這個結點是頭結點)才能把c插入到a的前面對吧。
那你試想下,如果沒有頭結點的話,那是不是還要判斷插入結點是第一個結點還是第一個結點之後。(你們想象下沒有頭結點的插入就知道了)
Line 47~49 這個是尋找要插入的位置的前一個結點
Line 50~51 申請一個新的結點,並把要插入的元素(現在是c)賦值到數據域,我們即將要把它插入到我們想要的位置。
Line 52~54 看下下面這個圖
node->next = pre->next;
將c的指針域指向到a
pre->next = node;
將pre結點(現在是頭結點)的指針域指向c
然後返回真,這就完成了一次插入操作,請注意,我們要插入一個結點,需要的是前一個結點。
Line 57~70 刪除操作
我們把剛纔的插入完C的表重新調整一下。
Line 59 是遍歷全部結點
Line 60 是找到要刪除的結點的前一個結點
Line 61 用指針q指向結點a,看圖
Line 62 比如現在找到了c(a的前一個結點),那我們要把a刪除,把c的指針域指向b結點即可
Line 63 這時結點a就沒有了任何存在的意義了,我們需要手動釋放它,這裏的Line 61~63的順序是不能換的,耐人尋味。爲什麼不能先釋放呢,因爲我們如果先釋放了,那我們c結點就找不到a結點的後一個結點b了
Line 72~78 由於有頭結點,所以判斷的條件next是否爲空。