题型一:从尾到头打印链表
方法一:递归方式
void printtailtohead1(ListNode* ppHead)//从尾到头打印链表
{
if (!ppHead)
return;
printtailtohead1(ppHead->pNext);
printf("%d->", ppHead->data);
}
方法二:遍历链表
思想:定义一个指针end指向NULL,再定义一个当前节点cur指向指向链表的最后一个节点,输出最后一个节点的数据,再将cur的值赋给end,相当于end前移一个节点,再次使cur->next=end;循环结束条件是end指向了头节点。如下图所示:
void printtailtohead2(ListNode* pHead)//从尾到头打印链表
{
ListNode* end = NULL;
while (pHead != end)
{
ListNode* cur = pHead;
while (cur->pNext != end)
{
cur = cur->pNext;
}
printf("%d->", cur->data);
end = cur;
}
}
题型二:删除无头链表的非尾节点(要求不能遍历链表)
分析:这个题的思想十分简单,不能遍历链表就意味着找到要删除这个节点的前一个节点,这样就给我们的删除带来了一些困难,不过,换一个方向思考,那是不是可以将要删除的这个节点的数据用其后一个节点覆盖呢?答案是可以的,并且这个的操作十分简单,简单的代码实现如下:
void DelNodeNoHead(ListNode* pos)//删除无头链表的非尾节点
{
assert(pos&&pos->pNext);
ListNode* Next = pos->pNext;
pos->pNext = Next->pNext;
pos->data = Next->data;
free(Next);
}
题型三:在一个无头链表前插入一个数据(要求不能遍历链表)
分析:由于不能遍历整个链表,所以就不能找到指定位置的前一个节点,所以插入也变得优点困难,但是换一中思路,如果就在当前节点后面插入一个链表,再将链表里面的数据交换,是不是就可以达到在指定位置前面插入一个节点,如下图所示:
void InsertNoHead(ListNode* pos,TypeDate x)//在指定为之前插入一个节点
{
ListNode* NewNode = BuyNode(pos->data);
NewNode->pNext=pos->pNext;
pos->pNext=NewNode;
pos->data = x;
}
测试代码如下:
testInsertNoHead()
{
ListNode* S = NULL;//初始化链表
ListNode* pos = NULL;
SListPushback(&S, 2);
SListPushback(&S, 4);
SListPushback(&S, 6);
SListPushback(&S, 8);
SListPushback(&S, 10);
SListPushback(&S, 12);
SListPushback(&S, 14);
SListPrint(S);
pos = Find(S, 8);
InsertNoHead(pos,7);
SListPrint(S);
}
题型四:单链表实现约瑟夫环:
分析:首先我们应该了解什么事约瑟夫环:
约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后 结果+1即为原问题的解。
在这里我们返回剩的最后一个人,看谁是最后的幸运者:
解决约瑟夫环的问题,首先要确定要思路,数到k的人要出列,那也就是说删除第k个节点,然后再继续循环,又从0开始数数,数到k,那么这个人就出列,也就是删除该位置的节点,循环结束条件是:当当前节点指向自己,也就能意味着只剩下了一个人了,返回这个人的值,看和自己推倒的结果是否是一致的。(为了构成环,我们需要将尾节点的next指向头节点),根据这个思路我们就可以很容易写出代码了,代码如下:
ListNode* JosephCycle(ListNode* pHead, int k)//约瑟夫环
{
ListNode* tail = pHead;
ListNode* cur = pHead;
if (pHead==NULL)
return NULL;
//构成环
while (tail->pNext)
{
tail = tail->pNext;
}
tail->pNext = pHead;
while (cur!=cur->pNext)
{
ListNode* NextNode = NULL;
int count = k;
while (--count)//循环count-1次
{
cur = cur->pNext;
}
NextNode = cur->pNext;
cur->data = NextNode->data;
cur->pNext = NextNode->pNext;
free(NextNode);
}
return cur;
}
测试代码如下:
testJosephCycle()
{
ListNode* S = NULL;//初始化链表
ListNode* pos = NULL;
SListPushback(&S, 1);
SListPushback(&S, 2);
SListPushback(&S, 3);
SListPushback(&S, 4);
SListPushback(&S, 5);
SListPushback(&S, 6);
SListPushback(&S, 7);
SListPushback(&S, 8);
pos = JosephCycle(S, 5);
printf("幸存者是:%d\n", pos->data);
}
题型五:逆置/反转单链表
方法一:迭代法,从头到尾改变单链表的指向,将NULL置为新的头节点,再将原先的头节点置为NULL;详细过程如图:
void Listreservalone(ListNode** ppHead)//逆置链表,迭代法
{
ListNode* Node1=*ppHead;
ListNode* Node2 = Node1->pNext;
ListNode* Node3 = Node2->pNext;
if ((*ppHead) == NULL||(*ppHead)->pNext==NULL)
{
return *ppHead;
}
while (Node2 != NULL)
{
Node2->pNext = Node1;
Node1 = Node2;
Node2 = Node3;
if (Node3 != NULL)
{
Node3 = Node3->pNext;
}
}
(*ppHead)->pNext = NULL;
(*ppHead) = Node1;
}
方法二:头删头插法,设置一个指针指向当前链表的头节点,用一个临时变量来保存当前节点。再创建一个新的头节点,将临时变量头插给给个新的头节点。在循环条件内,当前节点持续后移。这样就可以将这个链表逆置过来,这个链表的头节点就是新建的头节点。
ListNode* Listreservaltwo(ListNode* pHead)//逆置链表,头删头插的方法
{
ListNode* NewHead=NULL;
ListNode* tmp;
ListNode* cur=pHead;
while (cur)
{
tmp = cur;
cur = cur->pNext;
tmp->pNext = NewHead;//头插
NewHead = tmp;
}
return NewHead;
}
测试代码如下:
testListreservaltwo()
{
ListNode* S = NULL;//初始化链表
ListNode* head = NULL;
SListPushback(&S, 1);
SListPushback(&S, 2);
SListPushback(&S, 3);
SListPushback(&S, 4);
SListPushback(&S, 5);
SListPushback(&S, 6);
SListPushback(&S, 7);
SListPushback(&S, 8);
SListPrint(S);
head=Listreservaltwo(S);
SListPrint(head);
}
题型六:单链表的冒泡排序:
分析:链表的冒泡排序和普通排序并没有很大区别,思想都是一样的。我们需要创建三个指针,两个指针用来遍历整个链表,一个指针用来控制循环结束条件。,如下图所示 :
void Bubblesort(ListNode* pHead)//单链表的冒泡排序
{
ListNode* cur;
ListNode* Next;
ListNode* tail = NULL;
int flag = 0;
while (tail != pHead->pNext)
{
cur = pHead;
Next = pHead->pNext;
while (Next != tail)
{
if (cur->data > Next->data)
{
int tmp = cur->data;
cur->data = Next->data;
Next->data = tmp;
flag = 1;
}
cur = cur->pNext;
Next = Next->pNext;
}
tail = cur;//尾每次前移动一位
if (flag == 0)//表示一次都没有交换,则 本身就是有序的,就不需要遍历了
{
break;
}
}
}
测试代码如下:
testBubblesort()
{
ListNode* S = NULL;//初始化链表
SListPushback(&S, 1);
SListPushback(&S, 22);
SListPushback(&S, 3);
SListPushback(&S, 9);
SListPushback(&S, 10);
SListPushback(&S, 6);
SListPushback(&S, 7);
SListPushback(&S, 18);
Bubblesort(S);
SListPrint(S);
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章