有空头单向链表_(C语言实现)
本文主要是针对(含空头)单向链表进行增、删、改、查操作
创建一个结构体当做节点
struct Node
{
int iData;
struct Node* pNext;
};
定义空头指针
//空头
struct Node stHead = { 0,NULL };
空头不参加任何增、删,
增加:1.尾添加
此处和之前无空头链表操作只有稍微差别,咱们这次就不要尾指针了(当然你也可以尝试添加空的尾指针也是可以的),记住一定要先连后断
//尾添加
void AddToTail(struct Node* stHead, int iData)
{
//参数合法性检测
if (NULL == stHead)
return;
//申请节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
if (pTemp == NULL)
return;
//空间赋值
pTemp->iData = iData;
pTemp->pNext = NULL;
//节点连到链表
struct Node* pT = stHead;
//循环找到尾巴
while (pT->pNext != NULL)
pT = pT->pNext;
pT->pNext = pTemp;
//计数器++
//(*iNodeCount)++;
(stHead->iData)++;
}
增加:2.头添加
//头添加
void AddToHead(struct Node* stHead, int iData)
{
//参数合法性检测
if (NULL == stHead)
return;
//申请节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
if (pTemp == NULL)
return;
//空间赋值
pTemp->iData = iData;
pTemp->pNext = NULL;
//链接链表
pTemp->pNext = stHead->pNext;
stHead->pNext = pTemp;
//计数器++
(stHead->iData)++;
}
此时咱们链表的最简单的两个添加,已经完成,我们可以遍历链表来查看,并且释放链表
遍历链表
//遍历链表
void Look(struct Node stHead)
{
struct Node* pTemp = stHead.pNext;
printf("共有 %d 个数据: ", stHead.iData);
while (pTemp != NULL)
{
printf("%d ", pTemp->iData);
pTemp = pTemp->pNext;
}
putchar('\n');
}
释放链表
//释放链表
void FreeList(struct Node* stHead)
{
//参数合法性检测
if (NULL == stHead || 0 >= stHead->iData)
return;
struct Node* pTemp = stHead->pNext;
if (pTemp == NULL)
return;
while (pTemp != NULL)
{
//记录当前节点
struct Node* pT = NULL;
if (pT== NULL)
return;
pT = pTemp;
//节点下移
pTemp = pTemp->pNext;
//释放记录节点
free(pT);
}
//对应数据置NULL
stHead->pNext = NULL;
//*iNodeCount = 0;
stHead->iData = 0;
}
释放链表记得指针要置空哈
查找:1.根据下标查询
//根据下标查找节点
struct Node* FindNodeByIndex(struct Node* stHead, int iIndex)
{
if (NULL == stHead || stHead->iData <= 0 || iIndex < 0 || iIndex > (stHead->iData) - 1)
return NULL;
struct Node* pTemp = stHead->pNext;
for (int i = 0; i < iIndex; i++)
pTemp = pTemp->pNext;
return pTemp;
}
查找:2.根据数值查询
struct Node* FindNodeByData(struct Node* stHead, int iData)
{
if (NULL == stHead || stHead->iData <= 0)
return NULL;
struct Node* pTemp = stHead->pNext;
while (pTemp != NULL)
{
if (pTemp->iData == iData)
break;
pTemp = pTemp->pNext;
}
return pTemp;
}
升级版添加:1.在指定下标节点处添加节点
void AddByIndex(struct Node* stHead, int iPosIndex, int iIndex)
{
//参数合法性检测
if (NULL == stHead || iPosIndex > stHead->iData || iPosIndex < 0)
return;
//循环找位置
struct Node* pTemp = stHead;
for (int i = 0; i < iPosIndex; i++)
{
pTemp = pTemp->pNext;
}
//找到了 并添加
AddToHead(pTemp, iIndex);
pTemp->iData -= 1;
stHead->iData += 1;
}
升级版添加:2.在指定数值添加一个或者多个节点
看着很高大上,其实你只需要调用头添加即可,此时的头非彼头;
//指定数据后面添加一个节点
void AddBehandData(struct Node* stHead, int iPosData, int iData)
{
//参数合法性检测
if (NULL == stHead)
return;
//遍历 找节点
struct Node* pTemp = stHead->pNext;
while (pTemp != NULL)
{
if (pTemp->iData == iPosData)
break;
pTemp = pTemp->pNext;
}
//判断是否找到
if (NULL == pTemp)
printf("查无此数据");
else
{
AddToHead(pTemp, iData);
pTemp->iData -= 1;
stHead->iData += 1;
}
}
//指定下标位置添加 n 个节点
void AddBySomeIndex(struct Node* stHead, int iPosIndex, int iCount, int iData)
{
//参数合法性检测
if (NULL == stHead || iPosIndex > stHead->iData || iPosIndex < 0)
return;
//循环找位置
struct Node* pTemp = stHead;
for (int i = 0; i < iPosIndex; i++)
{
pTemp = pTemp->pNext;
}
//找到了 并添加
//循环插入
for (int i = 0; i < iCount; i++)
{
AddToHead(pTemp, iData);
pTemp->iData -= 1;
stHead->iData += 1;
}
}
修改:1.根据数值改变此节点数据
void ChangeByData(struct Node stHead, int iData, int iValue)
{
if (stHead.iData <= 0)
return;
//循环找到对应下标位置
struct Node* pTemp = stHead.pNext;
for (int i = 0; i < stHead.iData; i++)
{
if (pTemp->iData == iData)
{
//修改数据
pTemp->iData = iValue;
}
pTemp = pTemp->pNext;
}
}
修改:2.根据下标改变此节点
//根据下标修改修改节点的值
void ChangeByIndex(struct Node stHead, int iIndex, int iValue)
{
if (stHead.iData <= 0 || iIndex < 0 || iIndex >stHead.iData - 1)
return;
//循环找到对应下标位置
struct Node* pTemp = stHead.pNext;
for (int i = 0; i < iIndex; i++)
pTemp = pTemp->pNext;
//修改数据
pTemp->iData = iValue;
}
删除:1.删除指定下标节点
void DeleteByIndex(struct Node* stHead, int iIndex)
{
//参数合法性检测
if (NULL == stHead || iIndex < 0 || iIndex > stHead->iData - 1)
return;
//循环定位指定下标的前一个节点
struct Node* pTemp = stHead;
for (int i = 0; i < iIndex; i++)
{
pTemp = pTemp->pNext;
}
//节点扣下来
struct Node* pT = pTemp->pNext;
//链表重新连接
pTemp->pNext = pT->pNext;
//释放原节点
free(pT);
//节点数 -1
stHead->iData -= 1;
}
删除:2.删除指定数据节点
void DeleteByValue(struct Node* stHead, int iValue)
{
// 参数合法性检测
if (NULL == stHead || stHead->iData < 0)
return;
//循环定位指定数据的前一个节点
struct Node* pTemp = stHead;
if (pTemp == NULL)
return;
while (pTemp->pNext != NULL)
{
if (pTemp->pNext == NULL)
return;
if (pTemp->pNext->iData == iValue)
{
//记录被删除的节点
struct Node* pT = NULL;
if (pT == NULL)
return;
pT = pTemp->pNext;
//链表重新连接
pTemp->pNext = pT->pNext;
//释放原节点
free(pT);
//节点数 -1
stHead->iData -= 1;
continue;
}
pTemp = pTemp->pNext;
}
}
删除:3.根据数值删除此节点(只删除一个哟)
struct Node* DeleteOneDataByData(struct Node** pHead, struct Node** pEnd, int iData)
{
if (NULL == *pHead)
return NULL;
if ((*pHead)->iData == iData)
{
DeleteHead(pHead, pEnd);
return *pHead;
}
else if ((*pEnd)->iData == iData)
{
DeleteEnd(pHead, pEnd);
return *pHead;
}
else
{
//循环找节点
struct Node* pTemp = *pHead;
while (pTemp->pNext != NULL)
{
if (pTemp->pNext->iData == iData)
break;
pTemp = pTemp->pNext;
}
//判断
if (pTemp->pNext != NULL)
{
struct Node* pT = pTemp->pNext; //记录
pTemp->pNext = pT->pNext;
free(pT);
return *pHead; //return pTemp->pNext ----- pHead
}
else
{
printf("查无此节点\n");
return NULL;
}
}
}
下面是一个简单对链表去除重复元素的操作,主要通过两个指针(内指针和外指针),遍历链表,找到重复的直接删除,并连接上下一个节点即可。
(1)去重
void DeleteSome(struct Node* stHead)
{
if (NULL == stHead || stHead->iData <= 1)
return;
//循环遍历
struct Node* pWai = stHead->pNext;
if (NULL == pWai)
return;
while (pWai != NULL)
{
//跟后面的节点进行比较
struct Node* pNei = NULL;
if (NULL == pNei)
return;
pNei = pWai;
while (pNei->pNext != NULL)
{
if (pWai->iData == pNei->pNext->iData)
{
//删除节点
//1.记录节点
struct Node* pTemp = pNei->pNext;
//2.原位置进行新的链接
pNei->pNext = pTemp->pNext;
//3.释放节点
free(pTemp);
//4.节点数--
stHead->iData -= 1;
continue;
}
pNei = pNei->pNext;
}
pWai = pWai->pNext;
}
}
此时有空头的单向链表基本操作已经完成咯~