7-10 两个有序单链表求差集

这篇文章展示了一段C语言代码,使用双指针技术处理两个已排序链表,找到第一个链表中不存在于第二个链表的元素。代码中包含了创建链表、添加元素、删除元素以及打印链表的功能,特别地,删除操作是在不允许新开辟内存的条件下完成的。
摘要由CSDN通过智能技术生成

 

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int val;
    struct Node* next;
} Node, *List;

List add(List head, int val) {
    List p = (List)malloc(sizeof(Node));
    p->val = val;
    p->next = NULL;
    head->next = p;
    return p;
}

List Create() {
    List dummy = (List)malloc(sizeof(Node));
    dummy->next = NULL;
    dummy->val = -1;
    List head = dummy;
    int n;
    scanf("%d", &n);
    while(n--) {
        int num;
        scanf("%d", &num);
        head = add(head, num);
    }
    return dummy;
}

List Delete(List head, List p) {
    while(head->next) {
        if(head->next == p) {
            head->next = head->next->next;
            break;
        }
        head = head->next;
    }
    return head->next;
}

List DifferA(List dummy1, List head2) {
    List p1 = dummy1->next, p2 = head2;
    while(p1 && p2) {
        if(p1->val < p2->val) p1 = p1->next;
        else if(p2->val < p1->val) p2 = p2->next;
        else {
            p1 = Delete(dummy1, p1);
            p2 = p2->next;
        }
    }
    return dummy1->next;
}

void Print(List head) {
    while(head->next) {
        printf("%d ",head->val);
        head = head->next;
    }
    printf("%d\n", head->val);
}

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        List dummy1 = Create();
        List dummy2 = Create();
        List head = DifferA(dummy1, dummy2->next);
        Print(head);
    }
    return 0;
}

双指针思路:
p1 == A    p2 == B
思路: 在升序的情况下,双指针同时从表头开始移动,
当p1->val < p2->val时,必定是B中没有的 仅p1向后移动到临界点(两值相等处);
当p1->val == p2->val时,把该结点删除掉 别忘了同时向后移动;
当p1->val > p2->val时,不一定,要让p2移动到后面看看有没有相等的;

因为这题要求我们不要新开辟内存,所有我只有从删除的角度入手,(本来一直想着从覆盖的角度,怎么都觉得不妥,后来上网看到一张图,改变了我的思路)

 是吧,看到这个图,容易让人联想到把结点从链表中删除掉

没有这种特殊要求的话,我一般会新开一个,写起来比较方便(至少少一写del函数勒)

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int val;
    struct Node* next;
} Node, *List;

void print(List head) {
//     这题题目说了至少存在一个,可以不写
    if(head == NULL) {
        printf("NULL");
        return;
    }
    while(head->next) {
        printf("%d ", head->val);
        head = head->next;
    }
    printf("%d\n", head->val);
}

List add(List head, int num) {
    List p = (List)malloc(sizeof(Node));
    p->val = num;
    p->next = NULL;
    head->next = p;
    return p;
}

void create(List dummy, int n) {
    while(n--) {
        int num;
        scanf("%d", &num);
        dummy = add(dummy, num);
    }
}

List del(List dummy, List p1) {
    List head = dummy->next;
    if(p1 == head) {
        dummy->next = dummy->next->next;
        free(p1);
        return dummy->next;
    }
    for(List p = head; p; p = p->next) {
        if(p->next->val == p1->val) {
            p->next = p->next->next;
//          这个时候p->next已经不是你之前那个p->next
//          别混淆 => 写free(p->next)有问题 不如写下面的方便保险
            free(p1);
            return p->next;
        }
    }
}

void DifferA(List dummy, List p2) {
//    p1 == A    p2 == B
//    思路: 在升序的情况下,双指针同时从表头开始移动,
//    当p1->val < p2->val时,必定是B中没有的 仅p1向后移动到临界点(两值相等处);
//    当p1->val == p2->val时,把该结点删除掉 别忘了同时向后移动;
//    当p1->val > p2->val时,不一定,要让p2移动到后面看看有没有相等的;
    List p1 = dummy->next;
    while(p1 && p2) {
        if(p1->val < p2->val) {
            p1 = p1->next;
        }else if(p1->val > p2->val) {
            p2 = p2->next;
        }else {
            p1 = del(dummy, p1);
            p2 = p2->next;
        }
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        List dummy1 = (List)malloc(sizeof(Node));
        List dummy2 = (List)malloc(sizeof(Node));
        dummy1->next = NULL;
        dummy2->next = NULL;
        int n1, n2;
        scanf("%d", &n1);
        create(dummy1, n1);
        scanf("%d", &n2);
        create(dummy2, n2);
        DifferA(dummy1, dummy2->next);
        print(dummy1->next);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值