1)第一个节点不装数据作为链表头(永远不变),从第二个节点开始有数据
2)不使用尾指针,涉及尾部,循环寻找;目的是与之前写的不一样,更有意思!
3)操作原理和操作逻辑和无空头链表基本一样,多了空头,代码部分也会稍有不同
4)与无空头链表的区别:有空头一些操作会比无空头的简单一些
//单独创建空头链表节点
struct Chain Head = {0,NULL};
//或者
struct Chain *pHead = (struct Chain*)malloc(sizeof(struct Chain));
pHead->iData = 0;
pHead->pNext = NULL;
free(pHead);
上面两种创建空头的方法都可以,一样的。区别在于释放:第一种从第二个节点开始释放,第二种从头开始释放。
与struct Chain *Head
区别:*Head
是指针,Head
是空间
struct Chain Head = {0,NULL};
int iCount = 0; //计数
1)传参
添加修改头本身的数据,所以要传变量头的地址;加入节点计数器,要对其进行修改,所以要传它的地址;还有要添加的数据
void AddTail(struct Chain *Head,int *iCount,int iData){}
2)参数合法性检测
头肯定要存在!NULL
就是不存在;计数器不能小于0,也不能不存在
//参数合法性检测
if (NULL == Head || NULL == iCount || *iCount < 0)
return;
3)创建节点
struct Chain *pTemp = (struct Chain*)malloc(sizeof(struct Chain));
4)节点赋值
pTemp->iData = iData;
pTemp->pNext = NULL;
5)连到链表
struct Chain*pT = Head;
while (NULL != pT->pNext )
pT = pT->pNext;
//此时pT指向尾
pT->pNext = pTemp;//连到尾
6)计数器自增
(*iCount)++;
总代码:
void AddTail(struct Chain *Head, int *iCount, int iData)
{
if (NULL == Head || NULL == iCount || iCount < 0)
return;
struct Chain *pTemp = (struct Chain*)malloc(sizeof(struct Chain));
if (pTemp != NULL)
{
pTemp->iData = iData;
pTemp->pNext = NULL;
struct Chain*pT = Head;
while (NULL != pT->pNext )
pT = pT->pNext;
pT->pNext = pTemp;
(*iCount)++;
}
}
改变链表和个数,就要传递链表头和个数变量,和无空头链表相似,都要进行记录当前节点,节点下移,释放节点的操作,最后不要忘了赋空
void FreeChain(struct Chain *Head, int *iCount){
//合法性检测
if (NULL == Head || 0 == *iCount )
return;
//头节点不要释放
struct Chain *pTemp = Head->pNext ;
if (pTemp == NULL)
return;
//循环释放
while (pTemp != NULL){
//记录当前节点
struct Chain *pT = pTemp;
//节点下移
pTemp = pTemp->pNext;
//释放节点
free(pT );
}
Head->pNext = NULL;
*iCount = 0;
}
注意不要传头就行了
//这里传值也可以
void print(struct Chain *Head,int *iCount){
if (NULL == Head)
return;
//定义遍历变量
struct Chain *pTemp = Head;
//循环遍历
while (pTemp->pNext != NULL){
//跳过头节点
printf("%d ",pTemp->pNext ->iData );
pTemp = pTemp->pNext;
}
//输出记录的个数
printf("\n共有%d个节点\n",*iCount);
}
思路:直接在头的下个位置添加;新节点连在头的下一个位置,来一个新节点就加在头后面,上一次添加的节点前:新节点连到头,头指向原来的节点断开,新节点指向原来头连的节点。
void AddHead(struct Chain*Head,int iData, int *iCount)
{
if (NULL == Head || iCount == NULL )
return;
//创建
struct Chain *pTemp = (struct Chain*)malloc(sizeof(struct Chain));
if (pTemp == NULL)
return;
//赋值
pTemp->pNext = NULL;
pTemp->iData = iData;
//连接
pTemp->pNext = Head->pNext;
Head->pNext = pTemp;
//数量加1
(*iCount)++;
}
处理思路,处理逻辑基本和无空头链表类似
三种情况:
1)传参:修改链表传一级指针(头指针不变);传计数变量,增加节点并记录;传链表数据,要通过数据找到要添加的位置;还有要添加的数据。
void AddMid(struct Chain *pHead, int *iCount, int iData,int Data){}
2)合法性检测、循环找到链表数据的前一节点
if (NULL == pHead || iCount == NULL || *iCount == 0)
return;
//定义中间变量遍历链表
struct Chain *pT = pHead->pNext ;
while (NULL != pT)
{
if (pT->iData == Data)//找到前一节点
break;
pT = pT->pNext;
}
//此时pT指向要找的前一节点
3)判断是否找到
//判断是否找到
if (NULL == pT)
printf("未找到\n");
4)然后就开始申请节点,节点赋值,连接节点了
//申请节点
struct Chain *pTemp = (struct Chain*)malloc(sizeof(struct Chain));
if (pTemp == NULL)
return;
//节点赋值
pTemp->iData = iData;
pTemp->pNext = NULL;
//连接
pTemp->pNext = pT->pNext;
pT->pNext = pTemp;
(*iCount)++;
5)由于大链表可以说是由很多小链表组成,所以每在中间添加一个节点时,都可以说是头添加。
//传头就可,不过头节点不再是pHead,而是找的前一个节点
//这样就是头添加了
AddHead(pT,iCount, iData);
和有空头的添加类似,这里就不赘叙了
(1)
void AddIndex(struct Chain *pHead, int *iCount, int iIndex, int iData)
{
if (NULL == pHead || NULL == iCount || *iCount < 0)
return;
struct Chain *pTemp = (struct Chain *)malloc(sizeof(struct Chain));
if (pTemp == NULL)
return;
pTemp->iData = iData;
pTemp->pNext = NULL;
int Sign = 0;
struct Chain *pT = pHead;
while (pT != NULL)
{
if (Sign == iIndex)
break;
pT = pT->pNext;
Sign++;
}
pTemp->pNext = pT->pNext ;
pT->pNext = pTemp;
(*iCount)++;
}
(2)还有一种是在有在表头添加函数的基础上建立的
这种方法在说无空头链表时讲过
//在表头添加的函数
void AddHead(struct Chain*Head,int iData, int *iCount)
{
if (NULL == Head || iCount == NULL )
return;
//创建
struct Chain *pTemp = (struct Chain*)malloc(sizeof(struct Chain));
if (pTemp == NULL)
return;
//赋值
pTemp->pNext = NULL;
pTemp->iData = iData;
//连接
pTemp->pNext = Head->pNext;
Head->pNext = pTemp;
(*iCount)++;
}
void AddIndex(struct Chain *pHead, int *iCount, int iIndex, int iData)
{
if (NULL == pHead || NULL == iCount || *iCount < 0)
return;
//找位置
int Sign = 0;
struct Chain *pT = pHead;
while (pT != NULL)
{
if (Sign == iIndex)
break;
pT = pT->pNext;
Sign++;
}
//此时已找到
AddHead(pHead,iCount,iData);
}
上面我们已经知道在指定位置下插入一个节点的方法,那循环N次插入一个节点的函数,不就是插入N个了。
(1)最基本的方法就是直接将上面在指定下标位置添加一个节点的函数放在循环里
void MoreiData(struct Chain *pHead, int *iCount, int iIndex,int iData,int Num)
{
int i = 1;
while (i <= Num)
{
if (NULL == pHead || NULL == iCount || *iCount < 0)
return;
struct Chain *pTemp = (struct Chain *)malloc(sizeof(struct Chain));
if (pTemp == NULL)
return;
pTemp->iData = iData;
pTemp->pNext = NULL;
int Sign = 0;
struct Chain *pT = pHead;
while (pT != NULL)
{
if (Sign == iIndex)
break;
pT = pT->pNext;
Sign++;
}
pTemp->pNext = pT->pNext;
pT->pNext = pTemp;
(*iCount)++;
i++;
}
}
(2)利用在头添加的函数
在表头添加的函数如上
void MoreiData(struct Chain *pHead, int *iCount, int iIndex,int iData,int Num)
{
int i = 1;
while (i <= Num)
{
if (NULL == pHead || NULL == iCount || *iCount < 0)
return;
int Sign = 0;
struct Chain *pT = pHead;
while (pT != NULL)
{
if (Sign == iIndex)
break;
pT = pT->pNext;
Sign++;
}
AddHead(pT, iCount, iData);
i++;
}
}