1.反转一个单链表
方法一:不断的进行后删,前插操作。
void reaversal(SListNode **pphead)//不断后删前插操作
{
SListNode *head = *pphead;//此指针在每次循环中始终指向当前链表的头
SListNode *oldp = head;//此指针在每次循环中始终指向原本的头节点,不会改变方向
SListNode *tmp = head->next;//此指针在每次循环中始终指向要被后删再头插的节点
while (tmp)//如果tmp为空,则代表逆序结束,旧头的next已经是空的了,成为新链表的尾
{
oldp->next = tmp->next;//将tmp架空,实际是后删操作的一部分
tmp->next = head;//将tmp变成新的头,实际是头插操作的一部分
head = tmp;//换头
tmp = oldp->next;//让tmp变成下次循环中待删除的节点
}
*pphead = head;
}
方法二:让每个节点转指向<向后转>
void reaversal_1(SListNode **pphead)
{
SListNode *pre= *pphead;//被执行操作的前一个节点
SListNode *cur = pre->next;//被执行操作的节点
SListNode *nex = cur;//被执行操作的后一个节点,暂时指向cur,在循环开始时指向下一个节点
pre->next = NULL;//此时的头,将会是转化后的尾,这里是在设置链表尾节点
while (nex)
{
nex = nex->next;//先让nex变成下一个节点,之所以不放在最后,是因为会有nex为空的限制
cur->next = pre;//让原本指着后面的指到前面来(向后转)
pre = cur;//为了下次循环而传递数据,这里是设置下次循环的上一个节点(本次执行操作的节点将会成下次循环的上一个节点)
cur = nex;//同上(本次的下一个节点将会成为下次的被执行节点)
}
*pphead = pre;//循环跳出后cur和next都已经指向空,pre才是新的头
}
2.输入两个链表,找出他们的第一个公共结点
(单链表不可能分叉,因为一个结点只有一个指向)
思路分析:如果两个单链表相交,从第一个公共结点开始,后面的结点都相同。
1)遍历两个单链表,找出较长的链表比较短的链表多gap个结点。
2)让指向较长的链表的指针先遍历gap个结点。
3)然后,两个链表同时开始依次遍历。
4)如果遍历到相同的结点,返回结点。
#include<math.h>
SListNode *getIntersectionNode(SListNode *headA, SListNode *headB)
{
int lenA = 0;
int lenB = 0;
SListNode *cur=NULL;
SListNode *longer=headA;
SListNode *shorter=headB;
int gap;
int i;
for (cur = headA; cur; cur = cur->next)
{
lenA++;
}
for (cur =headB; cur; cur = cur->next)
{
lenB++;
}
gap = abs(lenA - lenB);
if (lenA < lenB)
{
longer = headB;
shorter = headA;
}
for (i = 0; i < gap; i++)
{
longer = longer->next;
}
for (; longer && shorter; longer = longer->next, shorter=shorter->next)
{
if (longer == shorter)
{
return shorter;
}
}
return NULL;
}
3.给定一个链表,返回链表开始入环的第一个结点。
如果链表无环,则返回NULL。
解题思路:
<数学模型>A和B同时在操场起点(环的开始)开始跑步,如果A的速度是B速度的两倍。那么他们会在起点(环的开始)相遇。
如果A和B同时从离操场起点(环的开始)1/3处(链表的头)开始跑,那么他们也会在离操场起点(环的开始)的1/3处(环中的一个结点)相遇。
可以想到:定义两个指针变量fast,slow。slow依次遍历,fast跳跃遍历 ,如果有相遇的地方,则证明链表中有环。在分别从链表头和相遇的结点进行依次遍历,相遇的地方就是入环的第一个结点。
SListNode *detectCycle(SListNode *phead)
{
SListNode *fast = phead;
SListNode *slow = phead;
while (fast&&slow&&fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
break;
}
}
for (; fast&&fast->next; fast = fast->next, phead = phead->next)
{
if (fast = phead)
{
return fast;
}
}
return NULL;
}
3.约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。最后一个人获胜。
int main()
{
SListNode *phead;//指向头结点
SListNode *plast;//指向尾结点
SListNode *cur;
SListInit(&phead);
int i;
int m = 50, n = 3;//50个人数到3就退出
SListPushFront(&phead, 50);//首次头插
plast = phead;//首次头插的结点最后会是尾部
for (i = m-1; i >=1; i--)//依次头插
{
SListPushFront(&phead, i);
}
plast->next = phead;//连接成环
cur = plast;//保持第一个被删除的结点与起始位置相差n-个,
for (m; m > 1; m--)//剩最后一个人循环退出
{
for (i = 1; i < n; i++)//遍历n-1找到要进行后删的结点
{
cur = cur->next;
}
SListEraseAfter(cur);//后删
}
printf("%d", cur->data);
free(cur);
system("pause");
return 0;
}