C语言数据结构——单链表知识应用(键盘输入打印链表的增删查改及去重操作)


根据上一节所学的知识,今天我们来做一道程序题——链表的应用

题目

请设计一个程序,允许用户通过键盘输入数据以创建一个链表结构。在此基础上,实现对该链表进行如下一系列操作:

  1. 增加节点操作:能够在链表的指定位置或按照特定规则插入新的节点。
  2. 删除节点操作:可依据给定的条件(如节点的值、节点的位置等)准确删除链表中的相应节点
  3. 链表销毁:当程序不再使用该链表时,需妥善处理链表所占用的内存,实现将链表彻底销毁,释放所有相关内存资源的功能。
  4. 去重操作:对链表中的数据进行检查,若存在重复的数据节点(依据节点特定数据域判断),则删除多余的重复节点,使得链表中每个数据值仅保留一份。
下面开始单独讲解每一段的知识

一、链表结构的定义

首先我们复习一下单链表的定义和结构

链表的图解
在这里插入图片描述

链表有一个头节点(图中的plist),它是链表的起始点,通过头节点的指针可以找到链表中的第一个实际数据节点,最后一个节点的指针通常指向空(NULL),表示链表的结尾。

//定义一个链表的结构
typedef struct Node
{
    int data;//链表的数据
    struct Node* next;
} Node;
 

typedef 这是 C 语言结构体一个关键字,用于给已有的数据类型定义一个新的别名,将 struct Node 这个结构体类型定义了一个新的名字 Node,这样在后续的代码中,我们就可以直接使用 Node 来表示这个结构体类型
int data表示链表的数据
struct Node* next 这也是结构体的一个成员变量,但它的类型是指向 struct Node 类型的指针。这个指针用于指向下一个节点,从而通过各个节点的 next 指针将多个节点连接起来形成链表。如果一个节点的 next 指针为 NULL,则表示该节点是链表的最后一个节点。

  • 接着在主函数(main)部分定义头结点
Node* head = NULL;
head = createNode();//头结点接收键盘输入的链表信息

二、链表的输入打印操作

1.键盘输入

  • 主函数中需要接收用户输入的链表数据,同时应用于下面的操作
head = createNode()
  • 在头文件中定义
Node* createNode();
  • Node* createNode()介绍

Node* createNode() 函数的主要功能是从用户通过键盘输入的数据来创建一个链表,并在创建完成后返回该链表的头节点指针,以便后续对链表进行其他操作(如打印、插入、删除等)可以通过这个头节点指针来访问整个链表。


Node* createNode()
{
    Node* head = NULL;
    Node* tail = NULL;
    int data;
    printf("请输入链表节点数据,输入 -1 结束输入:\n");
    scanf("%d", &data);
    while (data != -1)
    {
        Node* newNode = (Node*)malloc(sizeof(Node));
        if (newNode == NULL)
        {
            printf("内存分配失败");
            exit(1);
        }
        newNode->data = data;
        newNode->next = NULL;
        if (head == NULL)
        {
            head = newNode;
            tail = newNode;
        }
        else
        {
            tail->next = newNode;
            tail = tail->next;

        }
        scanf("%d", &data);
    }
    return head;
}

在函数开始处,首先定义了三个变量:

	Node* head = NULL;
    Node* tail = NULL;
    int data;
    

Node* head = NULL 用于指向即将创建的链表的头节点。初始化为 NULL,表示链表目前为空,还没有任何节点。
Node* tail = NULL 作用是指向链表的尾节点。初始化为 NULL,因为在开始创建链表时,还不存在尾节点。
int data
scanf(“%d”, &data);用于临时存储用户从键盘输入的每个节点的数据值。

接下来
  • 使用一个 while 循环来不断创建节点并添加到链表中
  • 循环中通过 malloc 函数动态分配内存来创建一个新的 Node 结构体类型的节点,即 newNode
  • malloc 创建成功则返回void* 类型的指针,需要将其强制转换成Node*类型避免后续不必要的麻烦
  • malloc创建失败则返回NULL;
while (data!= -1)
{
    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL)
    {
        printf("内存分配失败");
        exit(1);
    }
   
  • 然后将用户刚刚输入的数据值 data 赋值给新创建节点 newNode 的 data 成员变量,即 newNode->data = data,这样新节点就存储了用户输入的这个数据。
  • 接着将新节点的 next 指针初始化为 NULL,表示这个新节点目前暂时是链表的最后一个节点
newNode->data = data;
newNode->next = NULL;
然后

这里根据链表是否为空的状态来决定如何将新创建的节点添加到链表中:

if (head == NULL)
{
    head = newNode;
    tail = newNode;
}
else
{
    tail->next = newNode;
    tail = tail->next;
}
  • 如果链表当前为空(即 head 指针为 NULL),这意味着这是创建的第一个节点,那么将 head tail 这两个指针都指向这个新创建的节点,因为这个节点既是链表的头节点也是尾节点。
  • 如果链表不为空,那么先将当前尾节点(tail)的 next 指针指向新创建的节点,这样就通过 next 指针将新节点连接到了链表的末尾。然后再更新 tail 指针,使其指向新的尾节点,即 tail = tail->next,确保 tail 始终指向链表的实际尾节点
等等
  • 在这里,有没有读者跟博主有同一个疑问!?

在这里插入图片描述

那就是

Node* head = NULL;

开头已经定义了head == NULL为什么不直接直接执行if语句?

if (head == NULL)
{
    head = newNode;
    tail = newNode;
}

解答如下

  • 一开始我们定义 Node* head = NULL;,这就好比说我们先准备了一个空盒子(代表链表一开始是空的),用来装后面要创建的链表节点。
  • 然后进入循环创建节点,每次循环都要把新创建的节点添加到链表合适的地方
  • if (head == NULL) 这个判断不是只看最开始定义的那个 NULL,而是在每一次循环要添加新节点的时候,看看当前这个链表是不是还完全没有节点
  • 比如说第一次循环,链表确实还啥节点都没有,那就把新创建的节点放进空盒子里,并且让 head 和 tail 都指向这个新节点,这时候链表就有了第一个节点
  • 等第一次循环完了,第二次循环的时候,head 就已经指着第一次循环创建的那个节点了,说明链表已经有节点了呀,那就不能再像第一次那样放新节点了,而是要通过 else 部分的代码,把新创建的节点添加到已有节点的后面,也就是让链表继续变长。

总结一下
这个 if (head == NULL) 的判断就是在每次循环添加新节点时,搞清楚链表当时是啥情况(有没有第一个节点了),好把新节点放在正确的位置上哦

最后返回头结点指针
    return head;
}

这样子键盘输入就完成了

2.屏幕输出

  • 首先需要初始化一个指针 pcur,用来链接头结点
  • 接着遍历链表并打印节点数据
void PNode(Node* phead )
{
    Node* pcur = phead;
while (pcur!= NULL)
{
    printf("%d ->", pcur->data);
    pcur = pcur->next;
}
  • 最后加入打印链表结束标志(链表的尾节点)
printf("NULL\n");
}

这样子链表打印部分就完成了

三、链表的添加功能

接下来讲一讲链表的添加功能头插;尾插;指定一个数之前插入;指定一个数之后插入

1.头插

  • 头插就是在链表头结点之前插入数据
Node* insNodeHead(Node** phead, int data)
{
    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL)
    {
        printf("内存分配失败");
        exit(1);
    }
    newNode->data = data;//新数据赋值给结构体中的data
    newNode->next = *phead;//原来的旧头节点向后移动
    *phead = newNode;//data变为头结点
    return *phead;
}
  • 运行代码效果图
    在这里插入图片描述

  • 首先,使用 malloc 函数动态分配内存来创建一个新的 Node 结构体类型的节点 newNode

  • 然后,将传入的要插入的数据值 data 赋值给新节点 newNode 的 data 成员变量,这样新节点就存储了要插入的这个数据。

Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL)
{
    printf("内存分配失败");
    exit(1);
}
newNode->data = data;
  • 接下来,将新节点 newNode 的 next 指针指向当前链表的头节点(即 *phead 所指向的节点)。这一步的作用是让新节点的下一个节点成为原来的头节点,实现了将原来的头节点向后移动一位的效果。
  • 最后,将 *phead 指针更新为指向新创建的节点 newNode,这样新节点就成为了链表的新头节点,完成了在链表头部插入节点的操作。
newNode->next = *phead;
*phead = newNode;

最后返回头结点,头插结束

return *phead;

2.尾插

  • 尾插就是在链表尾结点之后插入数据
Node* insNodeTail(Node** phead, int data)
{
    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL)
    {
        printf("内存分配失败");
        exit(1);
    }
    newNode->data = data;
    newNode->next = NULL;
    if (*phead == NULL)
    {
        *phead = newNode;
        return *phead;
    }
    Node* current = *phead;
    while (current ->next !=NULL)
    {
        current = current->next;

    }
    current->next = newNode;
    return *phead;
}
  • 运行代码效果图
    在这里插入图片描述
  • 首先跟头插一样判断列表是否为空
  • 如果当前链表为空(即 *phead 为 NULL),说明这是要插入的第一个节点,那么直接将 *phead 指针指向新创建的节点 newNode
if (*phead == NULL)
{
    *phead = newNode;
    return *phead;
}

如果链表不为空,那么需要遍历链表找到当前的尾节点。通过定义一个指针 current 并初始化为 *phead,然后在 while 循环中,只要 current 节点的 next 指针不为 NULL,就将 current 指针移动到下一个节点,直到找到最后一个节点(即 current->next 为 NULL)

Node* current = *phead;
while (current ->next!=NULL)
{
    current = current->next;
}

找到尾节点后,将尾节点的 next 指针指向新创建的节点 newNode,这样就成功地将新节点插入到了链表的尾部。最后返回更新后的链表头节点指针,以便后续操作能获取到更新后的链表状态。

current->next = newNode;
return *phead;

3.指定一个数之前插入

图片讲解一下

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
代码实现

Node* insNodeBeforeTail(Node** phead, int data,int target)
{
    if (*phead == NULL)
    {
        printf("插入的链表为空");
        return *phead;
    }
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;

    if ((*phead)->data == target)//判断链表的头节点的数据值是否等于target,如果相等,要在链表的头节点之前插入新节点
    {
        newNode->next = *phead;
        *phead = newNode;
        return *phead;
    }
    Node* prev = NULL;
    Node* current = *phead;
    while (current->next != NULL)
    {
        prev = current;
        current = current->next;
    }
    prev->next = current;
    free(current);
    return *phead;
}


下面来详细讲解一下
if ((*phead)->data == target) // 判断链表的头节点的数据值是否等于target,如果相等,要在链表的头节点之前插入新节点
{
    newNode->next = *phead;
    *phead = newNode;
    return *phead;
}

  • 判断链表的头节点的数据值是否等于target,如果相等,要在链表的头节点之前插入新节点
Node* prev = NULL;
Node* current = *phead;
while (current->next!= NULL)
{
    prev = current;
    current = current->next;
}
  • 定义了两个指针:
  • prev:初始化为 NULL,它的作用是用来记录当前节点 current 的前一个节点,以便后续找到目标节点的前一个节点时进行插入操作。
  • current:初始化为 *phead,即从链表的头节点开始遍历。

最后插入新节点

prev->next = newNode;
newNode->next = current;
return *phead;

代码运行结果图
在这里插入图片描述

4.指定一个数之后插入

整体的思路与指定一个数之前插入的思路一样
在这里插入图片描述

Node* insNodeAfterTail(Node** phead, int data, int target)
{
    if (*phead == NULL)
    {
        printf("链表为空,无法插入\n");
        return *phead;
    }

    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL)
    {
        printf("内存分配失败");
        exit(1);
    }
    newNode->data = data;
    Node* current = *phead;
    while (current != NULL && current->data != target)
    {
        current = current->next;
    }

    if (current == NULL)
    {
        printf("未找到指定值的节点,无法插入\n");
        free(newNode);
        return *phead;
    }
    newNode->next = current->next;
    current->next = newNode;
    return *phead;
}

四、链表的删除功能

好嘞,下面来详细讲解一下链表的删除功能

1.链表的头删

首先检查链表是否为空

if (*phead == NULL)
{
    printf("删除的链表数据为空\n");
    return *phead;
}
  • 若链表不为空,接下来要进行删除头节点的操作。
  • 首先,定义一个指针 temp,并将其赋值为当前的头节点指针 *phead
  • 这样 temp 就指向了要删除的头节点。
  • 这一步很重要,因为后续需要通过 temp 来释放该节点所占用的内存。
  • 然后,将 *phead 指针更新为指向当前头节点的下一个节点,即 (*phead)->next。这一步实现了将链表的头节点 “向后移动” 一位的效果,使得原来头节点的下一个节点成为了新的头节点,从而在逻辑上删除了原来的头节点。
Node* temp = *phead;
*phead = (*phead)->next;

最后释放temp

free (temp);

2.链表的尾删

  • 首先检查链表是否为空及是否只有一个节点
if (*phead == NULL)
{
    printf("删除的链表数据为空\n");
    return *phead;
}
if ((*phead)->next == NULL)
{
    free(*phead);
    *phead = NULL;
}
    1. 遍历链表找到尾节点的前一个节点
Node* prev = NULL;
Node* current = *phead;
while (current ->next!= NULL)
{
    prev = current;
    current = current->next;
}
  • 3.删除尾节点并重新连接链表
prev->next = NULL;
free(current);
    1. 返回更新后的链表头节点指针
return *phead;

3.删除指定位置的数据


Node* delNodeValue(Node **phead, int value)
{
    if (*phead == NULL)
    {
        printf("删除的链表数据为空\n");
        return *phead;
    }
    if (value == 1)
    {
        return delNodeHead(*phead);
    }
    Node* pcur = NULL;
    Node* current = *phead;
    int i = 1;

    while (current != NULL && i < value)
    {

        pcur = current;// 在遍历过程中,将当前节点赋值给pcur,以便后续删除操作时能够正确连接链表
        current = current->next;
        i++;
    }

    if (current == NULL)
    {
        printf("指定位置超出范围\n");
        return *phead;
    }
    // 当找到了要删除的节点(current指向要删除的节点),将pcur的next指针指向current的下一个节点
    // 这样就跳过了要删除的节点,实现了从链表中删除该节点的目的
    pcur->next = current ->next;
    free(current);
    return *phead;

}

五、链表的销毁功能

下面来详细讲解一下链表的销毁功能
  • 首先,定义了两个指针:

  • current:将其初始化为 *phead,也就是让它指向链表的头节点。这个指针的作用是在遍历链表的过程中,依次指向每个要被释放内存的节点。

  • next:它将用于保存当前节点 current 的下一个节点的指针,以便在释放当前节点内存后,能够顺利地移动到下一个节点继续进行释放操作。

Node* current = *phead;
Node* next;
  • 在每次循环中,首先执行 next = current->next,这一步是将当前节点 current 的下一个节点的指针赋值给 next,这样就保存了下一个节点的位置信息,因为在释放当前节点内存后,我们还需要通过 next 指针来移动到下一个节点继续遍历。
  • 接着,调用 free 函数并传入 current 指针,这会释放当前节点 current 所占用的内存空间。释放内存是非常重要的操作,它可以避免内存泄漏,确保程序在运行过程中不会因为不断占用内存而导致内存耗尽等问题。
  • 最后,**将 current 指针更新为 next,**这样就使得 current 指针指向了刚才保存的下一个节点,准备进行下一次循环,对下一个节点进行同样的内存释放操作
next = current->next;
free(current);
current = next;
  • 当 while 循环结束后将链表头节点指针置为 NULL
*phead = NULL;

六、链表的去重功能

下面来详细讲解一下链表的去重功能
    1. 检查链表是否为空
if (*phead == NULL)
{
    return *phead;
}
    1. 开始遍历链表
Node* current = *phead;
Node* prev = NULL;

while (current!= NULL)
{
  • 然后,通过一个 while 循环来开始外层遍历链表,只要 current 指针不为 NULL,就说明还没有遍历完整个链表,需要继续进行去重操作
  • 3.内层遍历查找并删除当前节点的重复节点
Node* temp = current;
Node* nextNode = current->next;

while (nextNode!= NULL)
{
    if (nextNode->data == current->data)
    {
        
        temp->next = nextNode->next;
        free(nextNode);
        nextNode = temp->next;
    }
    else
    {
        temp = nextNode;
        nextNode = nextNode->next;
    }
}
  • 4. 更新外层遍历指针并继续外层遍历
    prev = current;
    current = current->next;
}

最后返回更新后的链表头节点指针

七、程序的所有源代码

1.函数文件Function.h

// 定义链表节点结构体
typedef struct Node 
{
    int data;
    struct Node* next;
} Node;

// 创建链表函数,按用户输入数据构建链表,返回头节点指针
Node* createNode();

// 打印链表函数,遍历并输出链表各节点数据
void PNode(Node* phead);

// 显示链表操作主菜单
int menu();

// 显示插入数据操作子菜单
int insmenu();

// 显示删除数据操作子菜单
int delmenu();

// 删除链表头节点函数,更新链表头,处理空链表情况
Node* delNodeHead(Node** phead);

// 删除链表尾节点函数,更新链表头,处理空链表及单节点链表情况
Node* delNodeTail(Node** phead);

// 删除链表中指定值节点函数,在链表中查找并删除该值节点

// 在链表头部插入节点函数,创建新节点插入头部,处理内存分配失败,
Node* insNodeHead(Node** phead, int data);

// 在链表尾部插入节点函数,创建新节点插入尾部
Node* insNodeTail(Node** phead, int data);

// 在链表中指定值节点之前插入新节点函数
Node* insNodeBeforeTail(Node** phead, int data, int target);

// 在链表中指定值节点之后插入新节点函数
Node* insNodeAfterTail(Node** phead, int data, int target);

// 销毁整个链表函数
Node* destroyNode(Node** phead);
//对链表去重操作
Node* removeDuplicates(head);

2.头文件text.h

#define  _CRT_SECURE_NO_WARNINGS
#pragma once

typedef struct Node
{
    int data;
    struct Node* next;
}Node;

Node* createNode()
{
    Node* head = NULL;
    Node* tail = NULL;
    int data;
    printf("请输入链表节点数据,输入 -1 结束输入:\n");
    scanf("%d", &data);
    while (data != -1)
    {
        Node* newNode = (Node*)malloc(sizeof(Node));
        if (newNode == NULL)
        {
            printf("内存分配失败");
            exit(1);
        }
        newNode->data = data;
        newNode->next = NULL;
        if (head == NULL)
        {
            head = newNode;
            tail = newNode;
        }
        else
        {
            tail->next = newNode;
            tail = tail->next;

        }
        scanf("%d", &data);
    }
    return head;
}

void PNode(Node* phead )
{
    Node* pcur = phead;
    while (pcur != NULL)
    {
        printf("%d ->", pcur->data);
        pcur = pcur->next;
    }
    printf("NULL\n");
}

int menu()
{
    int choose;
    printf("请选择对链表的操作:\n");
    printf("1. 删除数据\n");
    printf("2. 插入数据\n");
    printf("3. 销毁链表\n");
    printf("4. 对链表去重\n");
    printf("请输入你的选择:");
    scanf("%d", &choose);
    return choose;
}

int insmenu()
{
    int choose;
    printf("请选择插入数据的方式:\n");
    printf("1. 头插\n");
    printf("2. 尾插\n");
    printf("3. 指定一个数之前插入\n");
    printf("4. 指定一个数之后插入\n");
    printf("请输入你的插入操作选择:\n");
    scanf("%d", &choose);
    return choose;
}

int delmenu() 
{
    int delchoice;
    printf("1. 在头部删除节点\n");
    printf("2. 在尾部删除节点\n");
    printf("3. 删除指定位置的节点\n");
    printf("请输入你的删除操作选择: \n");
    scanf("%d", &delchoice);
    return delchoice;
}

Node* delNodeHead(Node ** phead)
{
    if (*phead == NULL)
    {
        printf("删除的链表数据为空\n");
        return *phead;
    }
    Node* temp = *phead;
    *phead = (*phead)->next;
    free (temp);
    return *phead;

}

Node* delNodeTail(Node** phead)
{
    if (*phead == NULL)
    {
        printf("删除的链表数据为空\n");
        return *phead;
    }
    if ((*phead)->next == NULL)
    {
        free(*phead);
        *phead = NULL;
    }
    Node* prev = NULL;
    Node* current = *phead;
    while (current ->next != NULL)
    {
        prev = current;
        current = current->next;
    }
    prev->next = NULL;
    free(current);
    return *phead;
}

Node* delNodeValue(Node **phead, int value)
{
    if (*phead == NULL)
    {
        printf("删除的链表数据为空\n");
        return *phead;
    }
    if (value == 1)
    {
        return delNodeHead(*phead);
    }
    Node* pcur = NULL;
    Node* current = *phead;
    int i = 1;

    while (current != NULL && i < value)
    {

        pcur = current;// 在遍历过程中,将当前节点赋值给pcur,以便后续删除操作时能够正确连接链表
        current = current->next;
        i++;
    }

    if (current == NULL)
    {
        printf("指定位置超出范围\n");
        return *phead;
    }
    // 当找到了要删除的节点(current指向要删除的节点),将pcur的next指针指向current的下一个节点
    // 这样就跳过了要删除的节点,实现了从链表中删除该节点的目的
    pcur->next = current ->next;
    free(current);
    return *phead;

}

Node* insNodeHead(Node** phead, int data)
{
    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL)
    {
        printf("内存分配失败");
        exit(1);
    }
    newNode->data = data;//新数据赋值给结构体中的data
    newNode->next = *phead;//原来的旧头节点向后移动
    *phead = newNode;//data变为头结点
    return *phead;
}

Node* insNodeTail(Node** phead, int data)
{
    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL)
    {
        printf("内存分配失败");
        exit(1);
    }
    newNode->data = data;
    newNode->next = NULL;
    if (*phead == NULL)
    {
        *phead = newNode;
        return *phead;
    }
    Node* current = *phead;
    while (current ->next !=NULL)
    {
        current = current->next;

    }
    current->next = newNode;
    return *phead;
}

Node* insNodeBeforeTail(Node** phead, int data,int target)
{
    if (*phead == NULL)
    {
        printf("插入的链表为空");
        return *phead;
    }
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;

    if ((*phead)->data == target)//判断链表的头节点的数据值是否等于target,如果相等,要在链表的头节点之前插入新节点
    {
        newNode->next = *phead;
        *phead = newNode;
        return *phead;
    }
    Node* prev = NULL;
    Node* current = *phead;
    while (current->next != NULL)
    {
        prev = current;
        current = current->next;
    }
    prev->next = current;
    free(current);
    return *phead;
}

Node* insNodeAfterTail(Node** phead, int data, int target)
{
    if (*phead == NULL)
    {
        printf("链表为空,无法插入\n");
        return *phead;
    }

    Node* newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL)
    {
        printf("内存分配失败");
        exit(1);
    }
    newNode->data = data;
    Node* current = *phead;
    while (current != NULL && current->data != target)
    {
        current = current->next;
    }

    if (current == NULL)
    {
        printf("未找到指定值的节点,无法插入\n");
        free(newNode);
        return *phead;
    }
    newNode->next = current->next;
    current->next = newNode;
    return *phead;
}

Node* destroyNode(Node **phead)
{
    Node* current = *phead;
    Node* next;
    while (current != NULL)
    {
        next = current->next;
        free(current);
        current = next;
    }
    *phead = NULL;
}

Node* RemoveDuplicates(Node** phead)
{
    if (*phead == NULL)
    {
        return *phead;
    }

    Node* current = *phead;
    Node* prev = NULL;

    while (current != NULL)
    {
        Node* temp = current;
        Node* nextNode = current->next;

        while (nextNode != NULL)
        {
            if (nextNode->data == current->data)
            {
                
                temp->next = nextNode->next;
                free(nextNode);
                nextNode = temp->next;
            }
            else
            {
                temp = nextNode;
                nextNode = nextNode->next;
            }
        }

        prev = current;
        current = current->next;
    }

    return *phead;
}

3.源文件text.c

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include "text.h"

int main()
{
	int choice;
	int delchoice;
	int inschoice;
	int choose;

	printf("请先输入一个链表\n");
	Node* head = NULL;
	head = createNode();
	system("cls");
	PNode(head);
	printf("你要对这个链表进行什么操作\n");

	do
	{
		choice = menu();

		switch (choice)
		{
		case 1:

			delchoice = delmenu();

			switch (delchoice)

			{

			case 1:
				system("cls");
				PNode(head);
				printf("删除头结点\n");
				delNodeHead(&head);
				printf("删除头结点之后的数据\n");
				PNode(head);
				break;

			case 2:
				system("cls");
				PNode(head);
				printf("删除尾结点\n");
				delNodeTail(&head);
				printf("删除尾结点之后的数据\n");
				PNode(head);
				break;

			case 3:
				system("cls");
				PNode(head);
				printf("请输入要删除的结点");
				int value;
				scanf("%d", &value);
				delNodeValue(&head,value);
				PNode(head);
				break;

			default:

				break;
			}
			break;

		case 2:

			inschoice = insmenu();

			switch (inschoice)
			{
			case 1:

				system("cls");
				PNode(head);
				printf("请输入头插要插入的数据:");
				int data;
				scanf("%d", &data);
				insNodeHead(&head, data);
				PNode(head);
				break;
			case 2:

				system("cls");
				PNode(head);
				printf("请输入尾差要插入的数据:");
				scanf("%d", &data);
				insNodeTail(&head, data);
				PNode(head);
				break;
			case 3:
				system("cls");
				PNode(head);
				printf("请输入指定的值:");
				int target;
				scanf("%d", &target);
				printf("请输入要插入的数据:");
				scanf("%d", &data);
				insNodeAfterTail(&head, data, target);
				PNode(head);
				break;
			case 4:
				system("cls");
				PNode(head);
				printf("请输入指定的值:");
				int target2;
				scanf("%d", &target2);
				printf("请输入要插入的数据:");
				scanf("%d", &data);
				insNodeBeforeTail(&head, data, target2);
				PNode(head);
				break;
			default:
				break;
			}
			break;

		case 3:

			system("cls");
			printf("正在销毁链表...\n");
			destroyNode(&head);
			printf("\n链表已销毁\n");
			break;
		case 4:
			system("cls");
			PNode(head);
			printf("对链表进行去重操作...\n");
			head = RemoveDuplicates(&head);
			printf("去重操作完成后的链表:\n");
			PNode(head);
			break;
		default:
			printf("无效的选择,请重新输入\n");
			break;
		}

	} while (choice!=3);
  
}
感谢你的阅读,觉得博主写的好的话记得三连 ╰(✿´⌣`✿)╯♡

在这里插入图片描述

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

珹洺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值