【20190410】【每天一道算法题】相交链表(链表)

版权声明:=================== 转载请注明出处======================= 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;
}

猜你喜欢

转载自blog.csdn.net/weixin_40583722/article/details/89226744