链表的基本题型主要就以下这几种,其他的基本是在这基础上引申出来,所以如果基本掌握这几种单向链表的题,链表基本没什么太大问题了。
1.删除无头非尾节点
2.链表的冒泡排序
3.反转链表
4.在当前节点前插入一个数据x
5.查找链表的中间节点。
6.删除单链表的倒数第K个节点(K>1&&K<总长度)
对于上面这6个问题,我们进行分析与解答。
1.删除无头非尾节点
其实思路也挺简单的,就是我们要把删除的节点后的节点的数据放到要删除的节点上,删除了删除的节点后的节点,然后让删除节点指向删除删除的节点后的节点后的节点。
接下来,我用图解为大家分析下。
代码实现如下:
void DelNotHead(Node* pos)
{
Node* del = NULL;
assert(pos->next != NULL); //断言,排除尾节点的情况
pos->data = pos->next->data; //让当前节点后面节点的数据赋给当前节点。
del = pos->next; //删除记录当前节点后的节点
pos->next = pos->next->next; //当前节点的nex指向删除节点的下一个节点。
free(del);
del = NULL;
}
2.链表的冒泡排序
在这里我们的思路是先有两个指针,一个头指针,一个尾指针,第一次从头进行冒泡到尾,第二次从头冒泡到最后一个节点的前一个节点,就这样一次进行下去,一直到冒泡到第一个节点和第二个节点。

void BubbleSort(pLinkList pList)
{
pLinkNode cur = NULL;
pLinkNode tail = NULL;
assert(pList);
cur = pList->pHead;
if ((pList->pHead == NULL)||(pList->pHead->next==NULL))
{
return;
}
while (cur != tail) //当尾指针不等于头指针时进行冒泡
{
while (cur->next != tail) //控制cur指针最后到的位置是倒数第二个节点
{
if (cur->data > cur->next->data)
{
datatype tmp = cur->data;
cur->data = cur->next->data;
cur->next->data = tmp;
}
cur = cur->next;
}
tail = cur;
cur = pList->pHead;
}
}
3.反转链表
对于反转链表,其实就是你把链表解下来然后重新排下序。
void Reverse(pLinkList plist)
{
pLinkNode tmp = NULL; //记录中间节点
pLinkNode cur = NULL; //记录链表的第一个节点
pLinkNode newnode = NULL; //记录翻转后的第一个节点
assert(plist);
cur = plist->pHead;
while (cur != NULL)
{
tmp = cur;
cur = cur->next;
tmp->next = newnode;
newnode = tmp;
}
plist->pHead = newnode;
}
4.在当前节点前插入一个数据x
在当前节点之前插入一个数据,按照常规思路坑定也是不行的,这时候我们就要像删除无头节点一样有一个思维:
我们可以把插入节点的数据放到新节点上,把新节点的数据放到插入节点的数据上。
这样我们就可以实现在当前节点前插入一个节点了。
void InsertFrontNode(pLinkNode pos, datatype x)
{
pLinkNode newnode = NULL;
assert(pos);
newnode = (pLinkNode)malloc(sizeof(LinkNode));
if (NULL == newnode)
{
printf("out of memory");
exit(EXIT_FAILURE);
}
newnode->data = pos->data;
pos->data = x;
newnode->next = pos->next;
pos->next = newnode;
}
5.查找链表的中间节点。
查找链表的中间节点,所采用的思路就是我们平时所说的快慢指针。
给一个快指针,让快指针每次移动两步,给一个慢指针,让慢指针每次移动一步,最后结果就是快指针移动到最后一个节点,慢指针最后移动到了中间的节点上。

pLinkNode FindMidNode(pLinkList pList)
{
pLinkNode fast = NULL;
pLinkNode slow = NULL;
assert(pList);
slow = fast = pList->pHead;
while (fast != NULL)
{
if (fast->next != NULL)
{
fast = fast->next->next;
}
else
{
break;;
}
slow = slow->next;
}
return slow;
}
6.删除单链表的倒数第K个节点(K>1&&K<总长度)
在这里,对于删除单链表的倒数第K个节点,我们采用的思路是首先给个front指针和back指针,让front指针移动K次,然后让front指针和back指针同时移动,一直到front指针指向为NULL,此时back指针指向的就是倒数第K个节点,然后我们就可以删除back节点,注意,这里所采用的删除的方法要和上面类似,采用交换删除的方式。
当然,在这里面请你考虑一些异常的情况!

void DelKNode(pLinkList pList, int k)
{
pLinkNode front = NULL;
pLinkNode back = NULL;
pLinkNode del = NULL;
assert(pList);
if (pList->pHead == NULL)
{
printf("链表为空!!\n");
return;
}
if (k == 1)
{
printf("K应当大于1\n");
return;
}
front = back = pList->pHead;
while (front != NULL)
{
k--;
if (k < 0)
{
back = back->next;
}
front = front->next;
}
if (k <= 0)
{
back->data = back->next->data;
del = back->next;
back->next = back->next->next;
free(del);
}
}