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); } }}