1.鏈表的結構體以及全局變量聲明函數
#include <stdio.h>
#include <stdlib.h>
// 建立Node結構體
struct Node
{
int a;
struct Node * pNext;
};
//鏈表頭尾指針
struct Node* g_pHead = NULL; //剛開始鏈表頭部爲null(頭部:內容,該節點的內容存儲)
struct Node* g_pEnd = NULL; //剛開始鏈表尾部爲null 頭尾都爲null,表示空頭鏈表指針
2.建立鏈表函數(插尾法和插頭法)io
①插尾插入法
//建立鏈表,在鏈表中增長一個數據,尾添加(g_pEnd發生變化,可是g_pHead不變化,只與第一個傳入的Temp有關)
void AddListTail(int a)
{
//建立一個結點
struct Node * pTemp = (struct Node*)malloc(sizeof(struct Node));
//結點數據進行賦值
pTemp->a = a;
pTemp->pNext = NULL;
//連接
if(NULL == g_pHead || NULL == g_pEnd) //也就是剛開始,頭尾都是空,其實寫一個就能夠,頭是空,尾就是空
{
g_pHead = pTemp; //此時pTemp的地址既是頭也是尾,在以後的調用中,g_pHead始終等於第一次傳入的pTemp變量
//g_pEnd = pTemp; //g_pEnd賦值成爲pTemp新結點
}
else//此時鏈表再也不爲空
{
g_pEnd->pNext = pTemp; //g_pEnd尾部指向新來的結點List
//g_pEnd = pTemp;//指向以後,g_pEnd下移成爲pTemp新的結尾結點
}
g_pEnd = pTemp;//在每一次調用函數後,g_pEnd都等於此時傳入的pTemp g_pHead g_pEnd 此時因爲是尾插入,g_pEnd地址指向尾部新增,而且以後g_pEnd變爲最後一個
}循環
在這裏有一點很巧妙,g_pHead = pTemp只是在第一次參數傳入的時候賦值,可是在第一次傳入參數的最後讓g_pEnd也等於pTemp,這樣作使在以後,g_pEnd指向下一個值的結構體指針也能被g_pHead使用遍歷
同時,若是去打印g_pHead以及g_pEnd的pNext地址能夠發現鏈表
(1)g_pHead的pNext永遠指向首結點的下一個地址數據
(2)g_pEnd的pNext是變化的,由於g_pEnd結點在變化,pNext指向當前的下一跳結點查詢
②插頭插入法
//建立鏈表,在鏈表中增長一個數據,頭添加(g_pHead發生變化,可是g_pEnd不變化,只與第一個傳入的Temp有關)
void AddListHead(int a)
{
//建立一個結點
struct Node * pTemp = (struct Node*)malloc(sizeof(struct Node));
//結點數據進行賦值
pTemp->a = a;
pTemp->pNext = NULL;
//連接
if(NULL == g_pHead || NULL == g_pEnd) //也就是剛開始,頭尾都是空,其實寫一個就能夠,頭是空,尾就是空
{
g_pHead = pTemp; //此時pTemp的地址既是頭也是尾,在以後的調用中,g_pHead始終等於第一次傳入的pTemp
g_pEnd = pTemp; //g_pEnd賦值成爲第一個傳入的pTemp,以後再也不改變
}
else//此時鏈表再也不爲空
{
g_pTemp->pNext = g_pHead;
g_pHead = g_pTemp; g_pHead g_pEnd 此時因爲是頭插入,新增的g_pTemp地址指向頭部,而且以後g_pHead變爲第一個
}
}
3.鏈表的遍歷
①所有遍歷
void ScanList()
{
struct Node *pTemp = g_pHead; //初始化*pTemp爲頭部,若是不初始化,則pTemp爲最後一位,在本案例爲10
while(pTemp != NULL)//當鏈表結點的內容指向null,說明遍歷結束
{
printf("%d\n", pTemp->a);
pTemp = pTemp->pNext; //每一次循環指向鏈表前一個結點
}
}
在main函數中
直接調用ScanList()
②查詢指定結點 經過返回結構體類型,而後經過結構體類型變量pFind來接收
struct Node * SelectNode(int a)
{
struct Node *pTemp = g_pHead; //初始化*pTemp爲頭部,若是不初始化,則pTemp爲最後一位,在本案例爲10
while(pTemp != NULL)//當鏈表結點的內容指向null,說明遍歷結束
{
if (pTemp->a == a)
{
return pTemp;
}
pTemp = pTemp->pNext; //每一次循環指向鏈表前一個結點
}
return NULL; // 若是找不到返回null
}
在main函數中
struct Node * pFind = SelectNode(-1);
if (pFind != NULL)
{
printf("%d\n", pFind->a);
}
else
{
printf("鏈表中沒有該值\n");
}
4.鏈表清空
①清空列表
void FreeList()
{
struct Node *pTemp = g_pHead; //初始化*pTemp爲頭部,若是不初始化,則pTemp爲最後一位,在本案例爲10
while(pTemp != NULL)//當鏈表結點的內容指向null,說明遍歷結束
{
struct Node * pt = pTemp;
pTemp = pTemp->pNext; //每一次循環指向鏈表前一個結點
free(pt);
}
// 頭尾清空
g_pHead = NULL;
g_pEnd = NULL;
}
在這裏,重要的是free要放在最後free
若是free(pTemp)再去指向,則pTemp已經爲空,沒有指針的做用,若是先指向以後直接free(pTemp)則會致使指向失敗
關鍵是經過結構體指針變量來接收以後,free該變量。最後千萬記得去頭尾清空,否則g_pHead以及g_pEnd變爲野指針,再也不是NULL
此時必定要置野指針爲NULL
5.指定位置插入結點
void AddListRand(int index, int a)
{
//鏈表爲空
if (NULL == g_pHead)
{
printf("鏈表沒有結點\n");
return;
}
//找位置
struct Node * pt = SelectNode(index);
if (NULL == pt)
{
printf("沒有指定結點\n");
return;
}
//有此結點
//給a建立結點
struct Node * pTemp = (struct Node*)malloc(sizeof(struct Node));
//給結點成員進行賦值
pTemp->a = a;
pTemp ->pNext = NULL;
//連接到鏈表上
if (pt == g_pEnd)
{
g_pEnd->pNext = pTemp;
g_pEnd = pTemp;
}
else
{
//先連
pTemp->pNext = pt->pNext;
//後斷
pt->pNext = pTemp;
}
}
6.刪除結點
①頭刪除
void DeleteListHead()
{
if (NULL == g_pHead)
{
printf("鏈表爲NULL,無需釋放\n");
return;
}
//記錄舊的頭
struct Node*pTemp = g_pHead;
//頭的下一個結點變成新的頭
g_pHead = g_pHead->pNext;
//釋放舊的頭
free(pTemp);
}
從鏈表的首項開始刪除
②尾刪除
void DeleteListEnd()
{
//判斷鏈表是否爲空
if (NULL == g_pEnd)
{
printf("鏈表爲NULL,無需釋放\n");
return;
}
//鏈表不爲空
//鏈表有1個結點
if (g_pHead == g_pEnd)
{
free(g_pHead);
g_pHead = NULL;
g_pEnd = NULL;
}
else
{
//找到尾巴前一個結點
struct Node * pTemp = g_pHead;
while (pTemp->pNext != g_pEnd)
{
pTemp = pTemp->pNext;
}
//找到了,刪除尾巴
//釋放尾巴
free(g_pEnd);
//尾巴前移
g_pEnd = pTemp;
//尾的下一個指針賦值NULL
g_pEnd->pNext = NULL;
}
}
從列表的尾部開始刪除,思想:首先從鏈表的首項開始遍歷,找到最後一項的前一個則中止循環
③指定位置刪除
void DeleteListRand(int a){ if (NULL == g_pHead) { printf("鏈表爲NULL,無需釋放\n"); return; } //鏈表有東西,找這個結點 struct Node* pTemp = SelectNode(a); if (NULL == pTemp) { printf("查無此結點\n"); return; } //找到了 //只有一個結點 if (g_pHead == g_pEnd) { free(g_pHead); g_pHead = NULL; g_pEnd = NULL; } //有兩個結點 else if (g_pHead->pNext == g_pEnd) { if (g_pHead == pTemp) { DeleteListHead(); } else { DeleteListEnd(); } } else //有多個結點 { if (g_pHead == pTemp) { DeleteListHead(); } else if (g_pEnd == pTemp) { DeleteListEnd(); } else { //找刪除結點的前一個結點 struct Node * pT = g_pHead; while (pT->pNext != pTemp) { pT = pT->pNext; } //找到了 //連接 pT->pNext = pTemp->pNext; //釋放 free(pTemp); } }}