关于“双递增链表合并”涉及的结构体内的指针思考

目录

合并链表代码

合并处理详细图解:


要求:A和B是两个单链表(带头结点),其中元素递增有序。设计一个算法将A和B归并成一个按元素值递增的有序链表C,C由A和B中的结点组成。


定义链表结点为:

typedef struct node{
    int val;
    struct node *next;
}Node;

创建单链表:

/*

**创建一个size个结点的链表并返回头结点地址

*/

Node *creat(int size)
{
    if(size <= 0)      //对参数的有效性进行检查
    {
        printf("please input the size in the range!");
        exit(-1);
    }
    Node *head,*r,*p;
    MALLOC(head);  //为了方便,我把molloc及其返回值检查封装成了一个宏
    printf("input the 1 node val:\n");
    scanf("%d",&head->val);
    p=head;
    for(int i=1; i<size; i++)
    {

        MALLOC(r);
        printf("input the %d node val:\n",i+1);
        scanf("%d",&r->val);
        p->next=r;  //p的next指向r结点
        p=r;        //p指向r结点
    }
    p->next=NULL;
    return head;
}

重点来了:假如通过 creat()函数创建了两个分别独立的链表,

链表1为1 -> 2 -> 3 -> 4 -> 5 -> NULL

链表2为1 -> 2 -> 3 -> NULL

很明显合并后的链表应该为:1 -> 1 -> 2 -> 2 -> 3 -> 3 -> 4 -> 5 -> NULL

 

那么你打算怎么修改两节点中的指针的指向呢?也就是 Node 结构体中的 struct node *next; 

很多人第一想法就是既然要修改指针,那当然要传递一个二重指针进去(此处不考虑引用),这样才能改变指针的指向,从而达到修改指针的目的。但是,在这里,情况有点特殊,因为需要被修改的指针它是在结构体里,属于结构体成员。

现在要解决的问题是:修改结构体成员指针指向,应该传递结构体的二重指针吗?如果就传一重指针行吗?先来看一下测试函数再来下结论,注意:这部分仅为测试函数,测试完即删除,与题目要求无关。

测试:

//并不能修改结构体中指针的指向(不会修改结构体中变量的值)

void testpoint(Test node,int b)
{
    printf("test in function b addr = %p\n",&b);
    node.next = &b;
}
//会修改结构体中指针的指向(也会修改结构体中变量的值)
void testpoint2(Test *node2,int b)
{
    printf("test*2 in function b addr = %p\n",&b);
    node2->next = &b;
}
//会修改结构体中指针的指向(也会修改结构体中变量的值)
void testpoint3(Test **node3,int b)
{
    printf("test*3 in function b addr = %p\n",&b);
    (*node3)->next = &b;
}

main函数:

    int a = 100,b = 8;

    Test test; //Test 和 Node 类似
    test.val = 10;
    test.next = &a;
    printf("test next addr = %p\n",test.next);
    testpoint(test,b);
    printf("test next addr = %p\n",test.next);
printf("\n******************************************************\n");
    Test *test2 = (Test *)malloc(sizeof(Test));
    test2->next = &a;
    test2->val = 10;
    printf("\ntest*2 next addr = %p\n",test2->next);
    testpoint2(test2,b);
    printf("test*2 next addr = %p\n",test2->next);
printf("\n******************************************************\n");
    Test *test3 = (Test *)malloc(sizeof(Test));
    test3->next = &a;
    test3->val = 10;
    printf("\ntest*3 next addr = %p\n",test3->next);
    testpoint3(&test3,b);
    printf("test*3 next addr = %p\n",test3->next);

运行后,对比结果

发现 testpoint2(test2,b);  testpoint3(&test3,b); 都是可以达到修改结构体成员指针指向的效果,所以我们不需要把简单问题复杂化,直接传一个 一重的结构体指针 就可以达到修改结构体成员指针指向的效果了。


所以接下来的

合并链表代码

可以这样写:

Node *comlink(Node *link1,Node *link2)  //一重的结构体指针作参
{
    if(link1 == NULL || link2 == NULL)
    {
        printf("link have null");
        exit(-1);
    }
    unsigned int flag = 0;
    Node *comlink,*r,*p;

    Node *link1tmp = link1;
    Node *link2tmp = link2;

    //当两个链表都没有到结尾,继续循环比较
    while(link1tmp != NULL && link2tmp != NULL )
    {
        if(link1tmp->val > link2tmp->val) //插入较小的link2值
        {
            r = link2tmp;
            link2tmp = link2tmp->next;  //link2指向自己链表的下一个结点
        }
        else    
        {
            r = link1tmp;
            link1tmp = link1tmp->next;
        }

        if(flag) 
        {
            p->next = r;  //修改原来链表中结点的指向(构建新的合并链表)
            p = r;           //指向当前结点
        }
        else  //仅执行一次,确定头结点
        {
            comlink = r;
            p = r;
            flag++;
        }
    }
    printf("while is done\n");

    if(link1tmp == NULL && link2tmp != NULL)
    {
        p->next = link2tmp;
    }
    else if(link1tmp != NULL && link2tmp == NULL)
    {
        p->next = link1tmp;
    }
    else    //两链表刚好比较完
    {
        p->next = NULL;
    }
    return comlink;
}

main函数:

int main()
{
    Node *linklist1 = creat(5);
    Node *linklist2 = creat(3);
    printlink(linklist1); //该函数用于打印链表各结点内容信息,方便验证
    printlink(linklist2);

    Node * comlnk = comlink(linklist1,linklist2);
    printlink(comlnk);

    printlink(linklist1); //结点间的指向已经被更改了,但头指针并未被改动
    printlink(linklist2);
    return 0;
}

运行结果:

顺便打印出 linklist1 和 linklist2 链表各节点的值发现链表的结点指向已经发生了变化,因为传入的只是结构体一重指针,所以并不会更改结构体本身的地址(要区分上面提到的 结构体成员指针的修改),当函数 comlink(linklist1,linklist2); 执行完之后 linklist 这两个指针还是指向原来的地方,所以打印出来的数据怪怪的,但是分析一下还是很容易理解的。

合并处理详细图解:

 

                         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值