题目:
// 逆向打印单链表
void PrintListFromTail2Head(PNode pHead);
// 逆向销毁单链表
void DestroyListFromTail2Head(PNode* pHead);
// 删除单链表的非尾结点
void DeleteNotTailNode(PNode pos);
// 非头结点前插入data
void InsertNotHead(PNode pos, DataType data);
// 单链表实现约瑟夫环
PNode JosephCircle(PNode pHead, size_t M);
// 单链表的逆置–前后指针
PNode ReverseList(PNode pHead);
// 单链表的逆置–头插法
PNode ReverseList(PNode pHead);
// 查找链表的中间结点—要求不能遍历单链表
PNode FindMidNode(PNode pHead);
源程序:
void PrintListFromTail2Head(PNode pHead)//逆向打印
{
if (pHead)
{
PrintListFromTail2Head(pHead->next);//运用递归的思想,找出最后一个节点,打印
printf("%d->", pHead->data);
}
}
void DestroyListFromTail2Head(PNode* pHead)//逆向销毁
{
if (*pHead)
{
DestroyListFromTail2Head(&((*pHead)->next));
free(*pHead);
*pHead = NULL;
}
}
图解:
void DeleteNotTailNode(PNode pos)
{
if (pos == NULL || pos->next == NULL)
return;
else //让pos保存pos下个节点的值,然后删除pos的下个节点
{
PNode pTemp = pos->next;
pos->data = pTemp->data;
pos->next = pTemp->next;
free(pTemp);
}
}
图解:
void InsertNotHeadNode(PNode pos, DataType data)
{
PNode PNewnode = NULL;
assert(pos);
PNewnode = ByeNode(data);
PNewnode->next = pos->next;
pos->next = PNewnode;
PNewnode->data=pos->data;
pos->data = data;
}
约瑟夫环是一个自杀环,是约瑟夫和他的朋友为了活下来而想出的一种办法: 包括他和他的朋友在内的41个犹太人,为了不成为敌方的俘虏而相约自杀,自杀的顺序是这样产生的,他们41个人围成一个圈,从其中任意位置开始报数,每次报到3的人自杀,然后从下一个人又开始从1报数。直到最后就会剩下1个人,约瑟夫和他的朋友就站在了最后剩下的两个位置,从而生存下来。
我们可以使用单链表来实现,先将单链表构建成一个环,每次删除掉第M个元素,直到链表只剩下一个节点,那么就返回这个节点。
需要考虑:链表为空—-直接返回
链表不空时:
①报数
②删节点
还需要特别注意是头结点,因为在删除的过程中,你可能删除掉头结点,所以最好接收最后剩下的一个节点,因为此时phead保存的节点
已经可能被释放掉了,所以不能再使用phead,而是使用pCur,因为pCur始终指向的是链表中可以访问到的当前节点。
图形解析:
PNode JosephCircle(PNode pHead, size_t M)
{
if (NULL == pHead)
{
return NULL;
}
PNode pCur = pHead;
PNode prev = pCur;
while (pCur != pCur->next)
{
size_t k = M;
while (--k)
{
pCur = pCur->next;
}
PNode pDel = pCur->next;
pCur->data = pDel->data;
pCur->next = pDel->next;
free(pDel);
}
return pCur;
}
第一种方法–三个指针
首先考虑的还是链表为空和只有一个节点的情况—-直接返回。
还有链表中只有两个节点时,这种情况刚好在循环外可以处理。
在逆置的过程中肯定要进行循环,找到最后一个节点。
第二种方法–头插法:
简单说明:
就是每次将原链表的头节点摘下来(pHead->next = newnode),然后头插在新链表中(此时需要更新新链表的头结点),然后原来的头结点继续向后走,因为之前已经将头结点后的节点保存下来了;循环执行,直到原链表只剩下一个节点时,直接将最后这个节点头插在新链表即可。
PNode ReverseList(PNode pHead)//指针法
{
if (NULL == pHead || NULL == pHead->next)
{
return pHead;
}
PNode prev = pHead;
PNode pCur = prev->next;
PNode pnext = pCur->next;
while (pnext)
{
pCur->next = prev;
prev = pCur;
pCur = pnext;
pnext = pnext->next;
}
pCur->next = prev;
pHead->next = NULL;
return pCur;
}
PNode ReverseList1(PNode pHead)//头插法
{
if (NULL == pHead || NULL == pHead->next)
{
return pHead;
}
PNode pCur = pHead->next;
PNode newNode = NULL;
while (pCur)
{
pHead->next = newNode;
newNode = pHead;
pHead = pCur;
pCur = pCur->next;
}
pHead->next = newNode;
newNode = pHead;
return newNode;
}
首先考虑:链表为空——返回NULL;
分为两种情况:
链表中有奇数个节点时,分析如图示:
链表中有偶数个节点时:
PNode FindMidNode(PNode pHead)
{
if (NULL == pHead || NULL == pHead->next)
{
return pHead;
}
PNode pSlow = pHead;
PNode pFast = pHead;
while (pFast && pFast->next)
{
pSlow = pSlow->next;
pFast = pFast->next->next;
}
return pSlow;
}