(数据结构C语言)链表去重

前言

大二菜鸡面临越来越近的期末考试,瑟瑟发抖。为了应付一下可怕未知的数据结构机试,本人想练习一下编程,于是打开学校OJ,从头开始练习,拿这道链表去重练手,但也做了好长时间(泪)。虽然困难重重,但最后还是独立将题目实现,有一丢成就感,于是也想写一篇博客来加深体会。这也算我的第一篇博客,毕竟来CSDN白嫖一年了(笑)。


一、题目要求

给定一个键值为整数的单链表 L,将键值的绝对值有重复的结点删除:即对任意键值 K,只有键值或其绝对值等于 K 的第一个结点被保留在 L 中。例如,下面单链表 L 包含键值 21、-15、15、7、-15,如下图(a)所示;去重后的链表 L 包含键值 21、-15、7,如下图(b)所示。
在这里插入图片描述
输入说明:
输入的第一行包含两个整数,分别表示链表第一个结点的地址和结点个数 n(1≤n≤100)。结点地址是一个非负的 5 位整数,NULL 指针用-1 表示。
随后 n 行,每行含 3 个整数,按下列格式给出一个结点的信息:
Address Key Next
其中 Address 是结点的地址,Key 是绝对值不超过 10000 的整数,Next 是下一个结点的地址。
输出说明:
输出的第一行为去重后链表 L 的长度,换行;接下来按顺序输出 L 的所有结点,每个结点占一行,按照 Address Key Next 的格式输出,间隔 1 个空格。

测试样例:

输入样例 1
00100 5
99999 7 87654
23854 -15 00000
87654 -15 -1
00000 15 99999
00100 21 23854
输出样例 1
3
00100 21 23854
23854 -15 99999
99999 7 -1

二、思路

先用一个数组将输入结点存储,此时结点乱序,在数组中对结点排完序之后,再用链表将输入结点存储,之后比较、删除结点,最后打印结点内容。

三、代码

代码如下:

#include<stdio.h>
#include<stdlib.h>
#define MAX 100
//定义结点结构体
typedef struct node
{
    int self_adr;
    int next_adr;
    int key;
    struct node *next = NULL;
}node;
//初始化
node *Init(){
    node *head = (node *)malloc(sizeof(node));
    head->next = NULL;
    return head;
}
//寻找当前结点q的直接前驱
node *Search(node *head, node *q){
    node *p = head->next;
    while(p->next!=q){
        p = p->next;
    }
    return p;
}
//求当前链表长度
int sum_length(node *head){
    node *p = head->next;
    int length, count = 0;
    while(p){
        count++;
        p = p->next;
    }
    length = count;
    return length;
}

int main(){
    int n, first_adr;
    int i,j,length;
    node NodeList[MAX];
    node temp;
    node *head, *p, *q;

    head = Init();
    q = head;

    scanf("%d%d",&first_adr,&n);
    
    for (i = 0; i < n;i++){
        scanf("%d%d%d",&NodeList[i].self_adr,&NodeList[i].key,&NodeList[i].next_adr);
    }
    //按照输入前后地址对结点排序
    for (i = 0; i < n;i++){
        for (j = i; j < n;j++){
            if(NodeList[j].self_adr == first_adr){
                temp = NodeList[i];
                NodeList[i] = NodeList[j];
                NodeList[j] = temp;
                first_adr = NodeList[i].next_adr;
                break;
            }  
        }
    }
    //用链表将这些结点连接
    for (i = 0; i < n;i++){
        p = (node *)malloc(sizeof(node));
        p = &NodeList[i];
        p->next = NULL;
        q->next = p;
        q = q->next;
    }

    q = head;
    p = q->next;

    while(p){
        q = p->next;
        
        while (q){
            if (q->key == p->key || q->key == -(p->key)){
                if(q->next == NULL){//此时为链表最后一个结点
                node *s = Search(head, q);
                s->next_adr = -1;
                s->next = NULL;
                }
            else{
                node *s = Search(head, q);
                s->next_adr = q->next->self_adr;
                s->next = q->next;
                }
            }
            q = q->next;
        }
        p = p->next;
    }
    
    q = head;
    length = sum_length(q);
    printf("%d\n",length);//打印结点个数
    //打印结点
    while(q->next){
        p = q->next;
        if(p->next_adr==-1)
            printf("%05d %d %d\n",p->self_adr,p->key,p->next_adr);
        else
            printf("%05d %d %05d\n",p->self_adr,p->key,p->next_adr);
        q = q->next;
    }

    return 0;
}

四、反思

中间对链表操作的地方在循环那里卡了好久,由于未对判定条件深思熟虑,在操作最后一个结点时导致循环无法跳出,此为代码片段:

			if(q->next == NULL){//此时为链表最后一个结点
                node *s = Search(head, q);
                s->next_adr = -1;
                s->next = NULL;
                }

总结

虽然是个简简单单的编程题,但本人还是费了好大力气,但还是有收获的。另外,这个解法肯定不是最优的写法,但我想用通俗易懂的方式写出来。如果有大佬看到这篇文章,若有时间,请对程序进行指正。
谢谢浏览!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值