单链表典型题目
1.判断两个单链表是否相交,求相交的那个结点
思路一:通过两个指针,直接跑到最后一个结点,判断两个结点的地址是否相等。 但是无法求得相交的那一个结点。
思路二:先求得两个链表的长度,求差值,指向长的链表的指针先跑差值的结点数,两个指针再同时向后跑,每跑一个结点,判断其地址是否相等,如果相等,则直接返回其中一个指针,即为相交的第一个结点。
LinkList TwoListIntersection(LinkList list1, LinkList list2)
{
DeterPointIsNull(list1);
DeterPointIsNull(list2);
int len1 = list1->length;
int len2 = list2->length;
LinkList p = list1;
LinkList q = list2;
if (len1 > len2)
{
for(int i = 0; i < len1 - len2; ++i)
{
p = p->next;
}
}
else
{
for (int i = 0; i < len2 - len1; ++i)
{
q = q->next;
}
}
while (p != NULL) //pq长度相等,只需要判断p或只需判断q即可
{
if (p == q) //如果地址相同,则就是要找的结点
{
return p;
}
p = p->next; //如果地址不同,pq都向后移,继续寻找
q = q->next;
}
return NULL; //当pq均为空,即查找完也没找到地址相同的,则不想交
}
2.判断-个单链表是否有环
static LinkList RingList(LinkList list)
{
DeterPointIsNull(list);
LinkList p = list, q = list;//p为慢指针 q为快指针
while (q != NULL)
{
p = p->next;
q = q->next;
if (q == NULL)
{
return NULL;
}
q = q->next;
if (p == q)
{
return p;
}
}
}
3.如果有环,返回入环的第一 个结点
LinkList IsRingList(LinkList list)
{
DeterPointIsNull(list);
//pNode是快慢指针相遇的结点,不一定是入环的第一个结点
LinkList pNode = RingList(list);
if (pNode == NULL)
{
return NULL;
}
LinkList p = pNode;
LinkList q = list;
while (p != q)
{
p = p->next;
q = q->next;
}
return p; //入环的第一个结点
}
4.O(1)删除结点p (p结点不是最后一一个结点)
void DeleteLinkListNode(LinkList list,LinkList p)
{
if (p == list || p == NULL || p->next == NULL)
{
return;
}
LinkList q = p->next;
p->data = q->data;
p->next = q->next;
free(q);
}
5.O(1)在结点P之前插入一个新的数据val
void InsertOfNode(LinkList list ,LinkList p, ElemType val)
{
if (list == NULL || p == NULL || p == list)
{
return;
}
LinkList s = _ApplyNode(p->data, p->next);
p->data = val;
p->next = s;
}
6.将单链表逆置 12345 54321
void ResverLinkList(LinkList list)
{
DeterPointIsNull(list);
//至少两个节点才需要逆置
if (list->length < 2)
{
return;
}
//分为三个指针 因为要逆序所以有一个必须先指向NULL
//另外两个是前后关系
LinkList s = NULL;
LinkList p = list->next;
LinkList q = p->next;
//三个指针完成,q是最快的指针,只需要每次加一,p在q的后面,s跟着p
while (p != NULL)
{
p->next = s; //先让p指向s
s = p; //s来到p的位置 s向前一步
p = q; //p来到q p向前一步
//如果q已经到了尾结点的下一个 再执行这一步就会出错
if (q != NULL)
{
q = q->next; //q向前一步
}
}
list->next = s;
}
7.返回倒数第k个结点
//思路一:如果有链表长度,则长度减k+1
//思路二:没有链表长度,使用两个指针p先走k个 q一个一个开始走 当p为空则q为求的结点
LinkList FindAfterK(LinkList list, int k)
{
DeterPointIsNull(list);
if (k <= 0||list->next==NULL)
{
return NULL;
}
LinkList p = list;
LinkList q = list;
for (int i = 0; i < k; ++i)
{
p = p->next;
if (p == NULL)
{
return NULL;
}
}
while (p != NULL)
{
p = p->next;
q = q->next;
}
return q;
}