版权声明:=================== 转载请注明出处======================= https://blog.csdn.net/weixin_40583722/article/details/89226744
问题:
编写一个程序,找到两个单链表相交的起始节点。
注意:
1. 如果两个链表没有交点,返回 NULL。.
2. 在返回结果后,两个链表仍须保持原有的结构。
3. 可假定整个链表结构中没有循环。
4. 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
思路与解答:
/* 1. 双指针遍历:O(m*n)超时
* 2. 两个链表长度不同时,先让更长的链表跳过前面若干个节点,两个指针再同时向后移动,O(n) */
/* 头结点:是头结点是首节点前的那个节点,并不存放数据的数据
头结点的数据类型和首节点的类型一模一样,未来方便对链表的操作
头指针:存放头结点地址的指针变量
首节点:存放第一个有效数据的节点
尾节点:存放最后一个有效数据的节点
*/
#include<stdio.h>
#include<stdlib.h>
struct ListNode *CreateList(void);
int length(struct ListNode *headx);
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB);
//链表节点声明
struct ListNode //节点是结构体类型,节点中的指针域是结构体指针类型,指向一个地址(下一个节点)
{
int val; //数据域
struct ListNode *next; //指针域
}; //有分号
int main(void)
{
struct ListNode *result = NULL; //函数返回类型是结构体指针类型,那么结果值也要是结构体指针类型(注意:结构体指针类型和结构体类型不是一个概念!)
struct ListNode *headA = NULL; //定义头指针,用来存放链表(存放链表的是头指针?)
struct ListNode *headB = NULL;
//创建两个链表(函数无输入)
headA = CreateList();
headB = CreateList(); //函数定义时形参用了void,那么调用时不可以再加入参数,void也不行!
result = getIntersectionNode(headA, headB); //函数调用时,参数只需要输入链表名即可!
printf("%d", result);
system("pause");
return 0;
}
struct ListNode *CreateList(void) //CreateList是函数名,struct ListNode当作一个整体,是我们上面自己定义的函数类型。
{
int len;
int i;
int val;
struct ListNode *pHead = (struct ListNode *)malloc(sizeof(struct ListNode));
if(NULL==pHead)
{
printf("分配失败,程序终止!\n");
exit(-1);
}
struct ListNode * pTail = pHead;
pTail->next = NULL;
printf("请输入需要生成的链接节点的个数:len=");
scanf("%d",&len);
for(i=0;i<len;++i)
{
printf("请输入第%d个节点的值:",i+1);
scanf("%d",&val);
struct ListNode * pNew = (struct ListNode *)malloc(sizeof(struct ListNode));
if(NULL==pNew)
{
printf("分配失败,程序终止!\n");
exit(-1);
}
pNew->val = val;
pTail->next = pNew;
pNew->next = NULL;
pTail = pNew;
}
return pHead; //函数类型是结构体指针类型,那么返回值也是结构体指针类型!
}
//长度求解正确,已验证!
int length(struct ListNode *headx)
{
int i;
struct ListNode *p = headx->next; //求长度,要从第一个元素开始,若初始化指向的是headx,那么最后求出来的长度要比实际长度大一,最后要return i-1,因为加了头指针的长度。
for(i=0; p!=NULL; i++)
p = p->next;
return i;
}
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) //struct ListNode表示数据类型,是一个整体,是我们自定义的结构体类型,可以用typedef给这个结构体类型重命名
{
if(headA==NULL || headB==NULL)
return NULL;
int lenA, lenB;
struct ListNode *pa = headA;
struct ListNode *pb = headB;
//求链表长度
lenA = length(headA);
lenB = length(headB);
//长链跳过某一长度
if(lenA > lenB)
{
for(int i=0; i<lenA-lenB; i++)
pa = pa->next;
}
else
for(int i=0; i<lenB-lenA; i++)
pb = pb->next;
//此时pa和pb应该指向同一长度的(子)链
while(pa!=NULL && pb!=NULL)
{
if(pa == pb) //需要节点完全相同,而不是val相同或者next相同(不全面)
return pa;
else
{
pa = pa->next;
pb = pb->next;
}
}
return NULL;
}