利用数据找节点
之前有涉及到利用下标找节点
struct Chain* FindMid(struct Chain *pHead, int Index){
if (NULL == pHead || Index < 0){
printf("头指针为0or下标无效\n");
return NULL;
}
else{
int Sign = 0;
while (NULL != pHead){
if (Sign == Index)
return pHead;
Sign++;
pHead = pHead->pNext;
}
return NULL;
}
}
利用数据找节点也很简单
1)定义利用数据找节点的函数
struct Chain*FindData(struct Chain **pHead, int iData){}
2)合法性检测
if (NULL == pHead)
return NULL;
3)遍历链表,并与要找的比较
while (NULL != pHead){
//循环遍历,若相等则是要找的值
if (pHead->iData == iData)
return pHead;
pHead = pHead->pNext;
}
4)若要是继续执行没有返回pHead
那就是没有找到
struct Chain*FindData(struct Chain *pHead, int iData)
{
if (NULL == pHead)
return NULL;
while (NULL != pHead){
//循环遍历,若相等则是要找的值
if (pHead->iData == iData)
return pHead;
pHead = pHead->pNext;
}
return NULL;
}
5)主函数检验
struct Chain *pTemp = FindData(pHead,3);
printf("%d ",pTemp->iData );
无空头链表的修改
找到指定节点,修改为指定数据
修改数据,而不是修改指针指向,所以传一级指针就可以
1)定义修改数据的函数
void ModiData(struct Chain *pHead, int IniData, int NewData){}
2) 合法性检测
void ModiData(struct Chain *pHead, int IniData, int NewData){
if (NULL == pHead)
printf("不合法错误\n");
else{}
}
3)替换数据
要先定义指针接住找到的返回值,然后将接住的值修改成新值就可以了
注意:找是从头找,找到第一个要找的值就返回(后面可能还会有相同的值)
void ModiData(struct Chain *pHead, int IniData, int NewData){
if (NULL == pHead){
printf("不合法错误\n");
return;
}
else{
struct Chain *pTemp = FindData(pHead, IniData);
if (NULL == pTemp)
printf("查无此节点\n");
else
pTemp->iData = NewData;
}
}
一次性修改多个数据
一次性修改多个,就是把多个相同的数据,修改为其他相同的数据
1)合法性检测
void ModiData(struct Chain *pHead, int IniData){
if (NULL == pHead ){
printf("查无此节点");
return;
}
}
2)修改多个数据
直接将源地址和要修改的地址比较,系统会从开始到最后都找一遍,找到之后,都修改为目标地址即可。
void ModiData(struct Chain *pHead, int IniData,int NewData){
if (NULL == pHead ){
printf("查无此节点");
return;
}
while (NULL != pHead){
if (pHead->iData == IniData)
pHead->iData = NewData;
pHead = pHead->pNext;
}
}
如何通过调用查找函数来修改多个?
这样的效率就非常低,一般都是用第一个!第二个知道,了解就好!
1)合法性检测
2)第一次查找
用改单个的方法改多个,无非就是将该单个的代码进行循环,就变成改多个的了。先在循环前先立好条件,肯定是查找的节点不为空吧,这样的话,首先我们就要先查找一次,这样查找的节点就不为空了,如下
//第一次找
struct Chain *pTemp = FindData(pHead,IniData);
if (pTemp == NULL)
{
printf("查无此节点\n");
return;
}
else
pTemp->iData = NewData;
//循环查找
while (NULL != pTemp)
{
pTemp = FindData(pHead, IniData);
//接着从此节点的下一个节点开始找
if (pTemp != NULL)
pTemp->iData = NewData;
}
无空头链表的删除
删除头
多层考虑:
1.链表无节点,直接结束!!
2.链表只有一个节点,释放节点,头、尾指针也要赋值为NULL
3.多个节点,记录第一个节点,头指针指向下一个节点,释放记录的节点。若只头指针指向下一个节点的话,之前的节点就找不到了,也无法释放!!
void DeleData(struct Chain **pHead, struct Chain **pTail)
{
//无节点
if (NULL == *pHead)
return;
//仅有一个节点
if ((*pHead)->pNext == NULL)
{
free(*pHead); //释放内容
*pHead == NULL, *pTail == NULL;
}
//不仅有一个节点
else
{
struct Chain *pTemp = *pHead;
*pHead = (*pHead)->pNext;
free(pTemp);
}
}
删除尾
多层考虑:
1.链表无节点,直接结束!!
2.链表只有一个节点,释放节点,头、尾指针也要赋值为NULL
3.循环找到尾节点的前一个节点,释放尾节点,尾指针指向上一个节点,新的尾节点的结构体指针赋值为NULL
void DeleTailData(struct Chain **pHead, struct Chain **pTail)
{
if (NULL == pHead)
{
printf("无节点\n");
return;
}
else
{
if (NULL == (*pHead)->pNext )
{
free(*pTail);
*pHead == NULL, *pTail == NULL;
}
else
{
//找尾节点前一个
struct Chain *pTemp = *pHead; //中间变量
while (pTemp->pNext !=*pTail)
{
pTemp = pTemp->pNext;
}
//已找到
free(pTemp->pNext);
//尾指针指向上一个
*pTail = pTemp;
//尾指针的下一个要赋空
(*pTail)->pNext = NULL;
}
}
}
删除指定数据
多层考虑:
1.参数合法性检测,若为空链表直接返回
2. 找节点,若是头节点,调用头删除;若是尾节点,调用尾删除;其他节点的话,就要循环找到要删除的前一个节点指向当前节点的数据来判断,具体见代码。
void DeleMidData(struct Chain **pHead,struct Chain **pTail,int iData)
{
if (NULL == *pHead)
return;
if ((*pHead)->iData == iData)
DeleHeadData(pHead,pTail);
else if ((*pTail)->iData == iData)
DeleTailData(pHead,pTail);
else
{
//定义中间变量装头指针
struct Chain *pTemp = *pHead;
//循环找要修改的前一节点
while (pTemp->pNext != *pHead)
{
//通过前一节点,指向要释放的节点的值
if (pTemp->pNext->iData == iData)
break;
pTemp = pTemp->pNext;
}
//判断pTemp->pNext是否为空,不为空才算找到
if (pTemp->pNext == NULL)
{
printf("未找到");
return;
}
else
{
//节点没名字,直接释放会丢失
struct Chain *pT = pTemp->pNext ;
//将上一节点的结构体指针指向要释放的节点的下一个节点
pTemp->pNext = pT->pNext;
free(pT);
}
}
}
删除指定数据的全部节点
同样是修改指针,要调用二级指针;删除链表的多个节点,要遍历链表,碰见相同的就删。
多层逻辑考虑:
1.如果是头或尾,调用删除头或尾的函数
2.如果是中间节点,那就那就调用删除中间节点的函数
3.删除多个,肯定要找多个,就要用到循环去找了,可以调用删除一个的函数,然后再循环。这一环节我们需要用到返回值,用返回值来决定是否还要继续遍历来找要删除的节点,若要删除的节点找完了,那就返回NULL
结束循环
1)判断合法性:链表是否为空,为空就不需要遍历
if (NULL == *pHead){
printf("pHead为空\n");
return NULL;}
2)如果想删除的节点是头节点,那头指针就指向下一个节点,然后从下一个节点继续遍历寻找,返回新的头即可
if ((*pHead)->iData == iData)
{
DeleHeadData(pHead, pTail);
return *pHead;
}
3)如果想删除的节点是尾节点,尾节点在程序逻辑中被删除后,不能直接返回NULL的,因为中间若是存在想删除的节点还没删掉(删除中间节点的代码在下面还未执行),所以要返回头指针继续遍历寻找中间的节点
else if ((*pTail)->iData == iData)
{
DeleTailData(pHead,pTail);
return *pHead;
}
4)寻找中间节点,和上面的删除一个节点的函数略有相同
else
{
//循环找节点
struct Chain*pTemp = *pHead;
while(pTemp->pNext != NULL)
{
if (pTemp->pNext->iData == iData)
break;
pTemp = pTemp->pNext;
}
//此时若已找到,就要判断是否为空,进而进行释放
if (pTemp->pNext != NULL)
{
struct Chain *pT = pTemp->pNext;
pTemp->pNext = pT->pNext;
free(pT);
//返回这个节点,下次直接从这个节点的下一节点遍历
return pTemp ;
}
else //没找到
{
printf("未找到\n");
return NULL;
}
}
上面的返回值为这个
return pTemp->pNext ;
时,当pTemp上的数要被删除时,外侧调用的是头删除(头删除代码块是没有接下一节点代码的,所以要需要删除头或尾的时候会造成断开的情况,即只要不涉及删头或者尾,用这个也可以),若后面不一遍遍从头遍历是与前面连不上的,而return pTemp ;
,则没调用头删除,后面也不用一次次从头遍历查找,效率非常高
删除一个的函数,已整改完成,对删除一个节点的也完全适用,如下:
struct Chain* ADeleAlliData(struct Chain **pHead,struct Chain **pTail,int iData)
{
if (NULL == *pHead){
printf("pHead为空\n");
return NULL;
}
if ((*pHead)->iData == iData){
DeleHeadData(pHead, pTail);
return *pHead;
}
else if ((*pTail)->iData == iData){
DeleTailData(pHead,pTail);
return *pHead;
}
else
{
//循环找节点
struct Chain*pTemp = *pHead;
while(pTemp->pNext != NULL){
if (pTemp->pNext->iData == iData)
break; //找到就返回
pTemp = pTemp->pNext;
}
if (pTemp->pNext != NULL){
struct Chain *pT = pTemp->pNext;
pTemp->pNext = pT->pNext;
free(pT);
return pTemp ;
}
else
return NULL;
}}
5)删除多个节点
第一步还是参数合法性检测
//合法性检测
if (NULL == *pHead) //链表为空
return ;
其次,先找一次,将找到的指针传给下一个
//定义中间变量,先找一次
struct Chain*pTemp = ADeleAlliData(pHead, pTail, iData);
最后,利用循环不断往下一个去找,由于pTemp
是不断指向要被删除的节点的,所以每次从它开始遍历(之前遍历的都找过了)会提升不少效率!
//pTemp == NULL就是没找到,直接跳过去
while (pTemp != NULL)
{
//继续找 pTemp 装的是想要删除的节点,
//我们每次不要都重新开始找,删除后,pTemp会指向下一个节点
pTemp = ADeleAlliData(&pTemp, pTail, iData);
}
根据下标删除节点
逻辑和根据数据删除节点相似,只不过一个找的是数据,一个找的是下标
逻辑:
1)合法性检测
if (NULL == *pHead)
return;
2)判断是不是头节点,是头节点就调用头删除;尾节点的话,就无法判断是不是尾了,所以要当作其他节点进行处理。
//下标为0就是头
if (0 == Index){
struct Chain *Temp = *pHead;
*pHead = (*pHead)->pNext;
free(Temp);
}
3)其他节点的处理
a. 调用根据下标查找前一节点的函数
b.找到节点
else{
struct Chain *pTemp = FindIndex(*pHead, Index - 1);
if (pTemp == NULL)
return;
struct Chain *pT = pTemp->pNext;
pTemp ->pNext = pT->pNext;
free(pT);
}