C语言数据结构之单链表与双链表的增删改查操作实现

目录
  • 前言
  • 单链表的增删改查
    • 定义结构体以及初始化
    • 增加结点
    • 删除结点
    • 查找修改结点
    • 移除结点
    • 最终效果
  • 双链表的基本操作
    • 初始化建表
    • 遍历双链表
    • 指定位置插入结点
    • 指定位置删除结点
    • 查找结点位置
    • 最终效果
  • 结语

前言

上篇博客分享了创建链表传入二级指针的细节,那么今天就分享几个c语言课程实践设计吧。这些程序设计搞懂了的话相当于链表的基础知识牢牢掌握了,那么再应对复杂的链表类的题也就能慢慢钻研了。学习是一个积累的过程,想要游刃有余就得勤学苦练!

单链表的增删改查

(1)项目需求

构造带有头结点的单链表数据结构,实现初始化、清空和销毁操作,在两端插入元素和删除元素操作并在链表中查找操作,在指定位置插入和删除元素操作,移除元素操作

(2)解决思路
①  定义节点类型,定义单链表类型,构造创建新节点的函数。

②  初始化、清空和销毁操作:初始化操作负责将参数指向的单链表类型变量初始 化为空链表。清空操作的作用是将一个链表清空。销毁操作负责销毁一个链表。

③  在两端插入元素和删除元素操作:包括从链表头部插入和删除元素,从链表尾 部插入和删除元素。

④  在链表中查找操作 : 查找操作用于在参数指向的链表中,查找首个值等于待插入 参数的元素。并返回结点的首地址,返回的地址可供使用者修改结点信息。

⑤  在指定位置插入和删除元素操作:插入和删除元素都涉及到前后位置指针的指 向问题,有多种解决方案。以插入元素为例,将元素插入指定位置、指定位置 之 4前和指定位置之后等。

⑥  移除元素:用于删除链表中所有满足某个条件的元素。删除单向链表中的结点 需要修改前驱结点的指针域,链表的首元结点没有前驱结点,需要考虑如何处理。

定义结构体以及初始化

typedef struct LinkList //typedef是重命名的含义,此时LinkList * 和 List 含义一致,都是指向结点的指针
{
    int data;//数据域
    LinkList* next;//指针域
}*List; //指向结点的指针
//初始化链表
void init_List(List &L)
{
    //初始化后链表第一个结点就是头结点
    L = (List)malloc(sizeof(LinkList));//为链表分配空间
    L->data = 0;//数据域为零
    L->next = NULL;//指针指向空
}

//清空链表
void clear_List(List &L)
{
    if (L->next != NULL)//如果头结点连着的第一个结点不为NULL
    {
        L->next = NULL;//置为NULL,此时链表只有头结点,相当于清空链表
    }
    printf("清空链表成功");
}
//销毁链表
void destory_List(List &L)
{
    if (L != NULL)//当头结点不为空时
    {
        free(L);//删除头结点地址
        L = NULL;//将指针指向NULL,彻底销毁链表
    }
    printf("销毁链表成功");
}

增加结点

1、头插

//头插法
void headAdd_List(List &L)
{
    List ptr = L->next;//ptr指针初始化指向首元结点,也就是除了头结点的第一个结点
    int value = 0;//用来赋值为插入结点的data属性
    printf("输入头插的结点值:");
    scanf("%d", &value);
    List s = (List)malloc(sizeof(LinkList));//s 为待插入结点
    s->data = value;//将value赋值给s data属性
    s->next = ptr;//s 指向 ptr,即指向头结点的下一个结点
    L->next = s;//L头结点指向s,那么现在s结点就插入
}

2、 尾插

//尾插法
void tailAdd_List(List &L)
{
    int value = 0;//用来赋值为插入结点的data属性
    printf("输入尾插的结点值:");
    scanf("%d", &value);
    List s = (List)malloc(sizeof(LinkList));//s 为待插入结点
    s->data = value;//将value赋值给s data属性
    List ptr = L->next;//ptr指针初始化指向首元结点,也就是除了头结点的第一个结点
    if (ptr == NULL)//此时链表为空
    {
        s->next = L->next;
        L->next = s;
    }
    else {
        List pre = NULL;//创建pre指针
        while (ptr)//当ptr不为NULL时
        {
            pre = ptr;//将pre指向ptr
            ptr = ptr->next;//ptr指向他的下一个结点
        }//循环结束时,pre指向链表最后一个结点,ptr指向最后一个结点的下一个结点
        s->next = ptr;//待插入s结点指向ptr
        pre->next = s;//将s结点插入到链表最后,尾插完成
    }
}

3、指定位置插入

//插入操作
void insert_List(List &L,int n,int data)
{
    List ptr = L->next;
    List pre = NULL;
    List s = (List)malloc(sizeof(LinkList));//s 为待插入结点
    s->data = data;//将形参列表的data数据赋值给s的data属性
    s->next = NULL;
    if (n<1)
    {
        printf("插入位置错误!");
    }
    else if (n == 1)
    {
        printf("调用头插法,请重写输入元素值:");
        headAdd_List(L);//如果插入第一个位置,调用头插法
    }
    else
    {
        for (int i = 1; i < n; i++)
        {
            pre = ptr;
            ptr = ptr->next;
        }//循环结束后,ptr指向待插入的位置,pre指向待插入位置的前一个位置
        s->next = ptr;//插入s结点
        pre->next = s;
    }
}

删除结点

1、头删

void headDelete_List(List &L)
{
    printf("执行头删:\n");
    List ptr = L->next;//ptr指针初始化指向首元结点,也就是除了头结点的第一个结点
    L->next = ptr->next;//直接让头结点指向首元结点的下一个结点,跳过首元结点就是删除
    delete ptr;//将首元结点地址删除
    ptr = NULL;//指针指向空,防止空指针异常
}

2、尾删

//尾删
void tailDelete_List(List& L)
{
    printf("执行尾删:\n");
    List ptr = L;//ptr指针指向头结点
    List pre = NULL;//创建结点pre
    while (ptr->next)//当ptr的下一个结点不为NULL时
    {
        pre = ptr;//将pre指向ptr
        ptr = ptr->next;//ptr指向他的下一个结点
    }//循环结束时,pre指向链表最后一个结点的前一个结点,ptr指向链表最后一个结点
    pre->next = NULL;//将pre的next指针置为空,删除掉
    free(ptr);//释放删除掉的ptr指针
}

3、指定位置删除 

void delete_List(List & L, int n)
{
    List ptr = L->next;
    List pre = NULL;
    if (n<1)
    {
        printf("删除位置有误!");
    }
    else if (n == 1)
    {
        headDelete_List(L);//调用头删
    }
    else
    {
        for (int i = 1; i < n ;i++)
        {
            pre = ptr;
            ptr = ptr->next;
        }//循环结束后,ptr指向待插入的位置,pre指向待插入位置的前一个位置
        pre->next = ptr->next;//删除该位置的结点
        delete ptr;//删除ptr地址
        ptr = NULL;//防止空指针异常
    }

}

查找修改结点

List find_List(int data,List &L)
{
    int i = 1;
    List ptr = L->next;
    while (ptr)//当结点不为空时
    {
        if (ptr->data == data)
        {
            printf("该元素在链表的位置为第 %d个\n",i);
            return ptr;//找到就返回地址
        }
        i++;
        ptr = ptr->next;//继续遍历
    }
    printf("链表中没有该元素\n");
    return NULL;
}

移除结点

//移除元素
void cancel_List(List &L,int n)
{
    List ptr = L->next;
    List pre = L;
    while (ptr)//ptr不空时
    {
        if (ptr->data == n)//如果和传进来的n相等
        {
            pre->next = ptr->next;//删除改结点
            delete ptr;//删除地址
            ptr = pre;//重新指向前一个结点
        }
        else {
            pre = ptr;//如果ptr不和n相等,让pre往后走
            ptr = ptr->next;//ptr向后遍历
        }
    }
}

最终效果

双链表的基本操作

初始化建表

typedef int ElemType;//将整型数据重命名为int
typedef int Status;//整型重命名为Status

//双链表的数据结构定义
typedef struct DouNode {
    ElemType data;               //数据域
    struct DouNode* head;        //前驱指针
    struct DouNode* next;        //后继指针
}DousList, * LinkList;// 结点指针
//双链表的创建
void CreateDouList(LinkList &L, int n)
{
    LinkList  ptr;
    int i;
    L = (LinkList)malloc(sizeof(DousList));    //为头结点申请空间
    L->next = NULL;
    L->head = NULL;
    L->data = n;//L->data记录结点的个数
    ptr = L;
    for (i = 0; i < n; i++)
    {
        int value = 0;
        scanf("%d",&value);
        LinkList me = (LinkList)malloc(sizeof(DouNode));
        me->data = value;    //节点数据域
        me->next = NULL;
        me->head = NULL;
        ptr->next = me;
        me->head = ptr;
        ptr = ptr->next;     //尾插法建表
    }
}

遍历双链表

//双链表的遍历
void DisPlayList(LinkList L)
{
    printf("当前链表数据为:\n");
    LinkList ptr= L->next;
    while (ptr)
    {
        printf("%d ",ptr->data);
        ptr = ptr->next;
    }
    printf("\n");
}

指定位置插入结点

void InsertNode(LinkList &L, int n, ElemType data)
{
    LinkList pre=NULL;
    LinkList ptr = L->next;
    LinkList me = (LinkList)malloc(sizeof(DouNode));
    me->head = NULL;
    me->next = NULL;
    me->data = data;
    if (n<1 || n>L->data)
    {
        printf("插入位置有误!");
        return ;
    }
    else if (n == 1)
    {
        ptr->head = me;
        me->next = ptr;
        L->next = me;
        me->head = L;
        L->data++;
    }
    else
    {
        for (int i = 1; i < n; i++)
        {
            pre = ptr;
            ptr = ptr->next;
        }
        ptr->head = me;
        me->next = ptr;
        pre->next = me;
        me->head = pre;
        L->data++;
    }

}

指定位置删除结点

Status DeleteNode(LinkList& L, int n, ElemType* v)
{
    LinkList ptr = L->next;
    if (n<1 || n>L->data)
    {
        printf("删除位置有误!");
        return -1;
    }
    else
    {
        for (int i = 1; i < n; i++)
        {
            ptr = ptr->next;
        }
        v= &ptr->data;
        ptr->head->next = ptr->next;
        ptr->next->head = ptr->head;

    }
    L->data--;
    return *v;
}

查找结点位置

void FindNode(LinkList L, ElemType data)
{
    int i = 0;
    LinkList ptr = L;
    while (ptr) {
        i++;
        ptr=ptr->next;
        if (ptr->data == data) {
            printf("该元素在链表中的位置为:%d\n",i);
        }
    }
}

最终效果

结语

链表的操作看着复杂其实也不复杂,和数组的区别就是需要动态分配内存空间,然后遍历有点小复杂罢了,多加练习就好了。

以上就是C语言数据结构之单链表与双链表的增删改查操作实现的详细内容,更多关于C语言 单链表 双链表的资料请关注我们其它相关文章!

(0)

相关推荐

  • C语言 单向链表的增删查改快速掌握

    目录 前言 一.创建 二.单向链表的函数声明 三.函数实现 1.创建节点 2.尾插节点 3.头插 4.尾删 5.头删 6.查找节点 7.修改 总结 前言 链表是线性表的链式存储结构,它可以以O(1)的时间复杂度进行插入或者删除,同时由于是链式结构相比顺序表而言,不会存在空间浪费的情况.而链表又分为带头单向链表,不带头单向链表,带头循环链表,不带头循环链表,带头双向循环链表,不带头双向循环链表,带头双向链表,不带头双向链表,总共有八种,其中结构最简单的是不带头单向链表,也是实现起来最容易出错的.并

  • C语言实现带头结点的链表的创建、查找、插入、删除操作

    本文实例讲述了C语言实现带头结点的链表的创建.查找.插入.删除操作.是数据结构中链表部分的基础操作.分享给大家供大家参考.具体方法如下: #include <stdio.h> #include <stdlib.h> typedef struct node { int data; struct node* next;// 这个地方注意结构体变量的定义规则 } Node, *PNode; Node* createLinklist(int length) { int i = 0; PNo

  • C语言中单链表的基本操作指南(增删改查)

    目录 1.链表概述 2.链表的基本使用 2.0 准备工作 2.1 创建节点(结构体) 2.2 全局定义链表头尾指针 方便调用 2.3 创建链表,实现在链表中增加一个数据(尾添加)----增 2.4 遍历链表 -----查 2.5 查询指定的节点 (遍历 一个个找) 2.6 链表清空------全部删除 2.7.在指定位置插入节点 ----在指定位置增 2.8尾删除----删 2.9 删除头------删 2.10 删除指定节点 3. 测试主程序 总结 1.链表概述 链表是一种常见的数据结构.它与

  • C语言之单链表的插入、删除与查找

    单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.要实现对单链表中节点的插入.删除与查找的功能,就要先进行的单链表的初始化.创建和遍历,进而实现各功能,以下是对单链表节点的插入.删除.查找功能的具体实现: #include<stdio.h> #include<stdlib.h> #include<string.h> typedef int ElemType; /** *链表通用类型 *ElemType 代表自定义的数据类型 *struct

  • C语言 数据结构双向链表简单实例

    双向链表的基本操作 1.利用尾插法建立一个双向链表. 2.遍历双向链表. 3.实现双向链表中删除一个指定元素. 4.在非递减有序双向链表中实现插入元素e仍有序算法. 5.判断双向链表中元素是否对称若对称返回1否则返回0. 6.设元素为正整型,实现算法把所有奇数排列在偶数之前. 7.在主函数中设计一个简单的菜单调试上述算法. 实例代码: //排序的时候因为没有说明奇数和偶数需不需要各自再排序,我就没有排序,只是将奇数放在偶数后面. //创建链表的时候,因为这个实验没有要求输出链表的长度,所以我就输

  • C语言数据结构之单链表与双链表的增删改查操作实现

    目录 前言 单链表的增删改查 定义结构体以及初始化 增加结点 删除结点 查找修改结点 移除结点 最终效果 双链表的基本操作 初始化建表 遍历双链表 指定位置插入结点 指定位置删除结点 查找结点位置 最终效果 结语 前言 上篇博客分享了创建链表传入二级指针的细节,那么今天就分享几个c语言课程实践设计吧.这些程序设计搞懂了的话相当于链表的基础知识牢牢掌握了,那么再应对复杂的链表类的题也就能慢慢钻研了.学习是一个积累的过程,想要游刃有余就得勤学苦练! 单链表的增删改查 (1)项目需求 构造带有头结点的

  • Java语言实现对MySql数据库中数据的增删改查操作的代码

    简单说操作的步骤: 1.连接数据库 2.将SQL语句发送到数据库 3.执行SQL语句 这里举个例子: 在一个数据库中有个students表,表中有学号(Id),姓名(Name),性别(Sex),地址(Address),电话(Phone),专业(Dept). 这里把这个表写成一个学生信息类(Info_student) (请先确保看了例子说明,不然代码有的地方可能看不明白) 要实现操纵我们首先得连接数据库,因为每个操作都要进行连接操作,所以我们直接把连接的操作封装在一个类中,需要连接的时候直接调用可

  • java实现单链表增删改查的实例代码详解

    package 数据结构算法.链表; /* *定义节点 * 链表由节点构成 */ public class Node<E> { private E e; //数据data private Node<E> next; //指向下一个节点 public Node() { } public Node(E e) { this.e = e; } public Node<E> getNext() { return next; } public void setNext(Node&l

  • Java如何实现单链表的增删改查

    一.新建学生节点类 Stu_Node节点包含: 学号:int num; 姓名:String name; 性别:String gender; 下一个节点:Stu_Node next; 为了便于打印节点内容需要重写toString方法 class Stu_Node{ int num; String name; String gender; Stu_Node next; @Override public String toString() { return "Stu_Node{" + &qu

  • Vue数据增删改查与表单验证的实现流程介绍

    目录 1. 准备工作 2. 弹出窗口 3. 新增更新功能 4. 删除功能 5. 表单验证 6. 接口文档 1. 准备工作 后台服务接口,对书本的增删改查操作 2. 弹出窗口 进入ElementUi官网, 找到Dialog对话框,可以参考“嵌套表单的dialog”实现. 该步骤先实现弹出窗口的前端逻辑,并不会调用后台接口服务进行实际的业务操作. BookList.vue <!-- 弹出窗口:增加和修改书本信息共用一个弹出窗口,需要根据用户的选择动态的设置弹出窗口的标题 :tile 通过绑定值的方式

  • C语言数据结构之单链表的实现

    目录 一.为什么使用链表 二.链表的概念 三.链表的实现 3.1 创建链表前须知 3.2 定义结构体 3.3 申请一个节点 3.4 链表的头插 3.5 链表的尾插 3.6 链表的尾删 3.7 链表的头删 3.8 寻找某节点 3.9 在指定节点前插入节点 3.10 删除指定节点前的节点 3.11 链表的销毁 一.为什么使用链表 在学习链表以前,我们存储数据用的方式就是数组.使用数组的好处就是便于查找数据,但缺点也很明显. 使用前需声明数组的长度,一旦声明长度就不能更改 插入和删除操作需要移动大量的

  • C语言数据结构之单链表存储详解

    目录 1.定义一个链表结点 2.初始化单链表 3.输出链表数据 4.完整代码 如果说,顺序表的所占用的内存空间是连续的,那么链表则是随机分配的不连续的,那么为了使随机分散的内存空间串联在一起形成一种前后相连的关系,指针则起到了关键性作用. 单链表的基本结构: 头指针:永远指向链表第一个节点的位置. 头结点:不存任何数据的空节点,通常作为链表的第一个节点.对于链表来说,头节点不是必须的,它的作用只是为了方便解决某些实际问题. 首元结点:首个带有元素的结点. 其他结点:链表中其他的节点. 1.定义一

  • C语言数据结构之单链表操作详解

    目录 1.插入操作 2.删除操作 3.查找操作 4.修改操作 5.完整代码 1.插入操作 (1)创建一个新的要插入的结点 (2)将新结点的 next 指针指向插入位置后的结点 (3)将插入位置前的节点指针 next 指向新的结点 注意:步骤(2)(3)的顺序不能颠倒,否则会导致插入位置后的部分链表丢失. 插入位置一共分三种,分别是头部插入.中间插入和尾部插入. 如图: 代码: link* insertElem(link* p,int elem,int pos){ link* temp = p;/

  • Go语言数据结构之单链表的实例详解

    目录 任意类型的数据域 实例01 快慢指针 实例02 反转链表 实例03 实例04 交换节点 实例05 任意类型的数据域 之前的链表定义数据域都是整型int,如果需要不同类型的数据就要用到 interface{}. 空接口 interface{} 对于描述起不到任何的作用(因为它不包含任何的method),但interface{}在需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值. 一个函数把interface{}作为参数,那么它可以接受任意类型的值作为参数:如果一个函数返回i

随机推荐