C++深入分析讲解链表

链表的概述

1、数组特点

1、空间连续、元素类型相同、通过下标快速访问

2、静态数组:空间一旦确定不能更改(动态数组除外)

3、静态、动态数组 插入删除元素 需要移动大量数据

2、链表的概述

链表是一种物理存储上非连续,数据元素的逻辑连续通过链表节点中的指针变量保存下个节点的地址,实现的一种线性存储结构。

3、链表的特点

链表由一系列节点(链表中每一个元素称为节点)组成,节点在运行时动态生成(malloc,calloc),每个节点包 括两个部分:

数据域:存放节点数据(核心)

指针域:结构体指针变量 保存下一个节点的地址

静态链表

#include <stdio.h>
//设计节点类型
typedef struct stu
{
    //数据域
    int num;
    char name[32];
    float score;
    //指针域
    struct stu *next;
}STU;
int main(int argc, char const *argv[])
{
    //静态链表的节点 不是从堆区申请
    STU node1={100, "lucy", 77.7f};
    STU node2={101, "bob", 66.7f};
    STU node3={102, "tom", 55.7f};
    STU node4={103, "hehe", 74.7f};
    STU node5={104, "xixi", 73.7f};
    //构建成链表
    STU *head = NULL;
    head = &node1;
    node1.next = &node2;
    node2.next = &node3;
    node3.next = &node4;
    node4.next = &node5;
    node5.next = NULL;
    //遍历链表(从头节点  逐个节点遍历)
    STU *pb = head;
    while(pb != NULL)
    {
        printf("%d %s %f\n", pb->num, pb->name, pb->score);
        //移动到下一个节点
        pb = pb->next;
    }
    return 0;
}

链表的操作

增、删、改、查

学生管理系统 讲解链表

1、链表插入节点

帮助信息函数:

void help(void)
{
    printf("******************************\n");
    printf("* insert:插入链表节点        *\n");
    printf("* printf:遍历链表节点        *\n");
    printf("* search:查询链表节点        *\n");
    printf("* delete:删除链表节点        *\n");
    printf("* free:释放链表节点          *\n");
    printf("* quit:遍历链表节点          *\n");
    printf("******************************\n");
    return;
}

头部之前插入节点

STU* insert_link(STU *head, STU tmp)
{
    //为插入的节点申请空间
    STU *pi = (STU *)calloc(1,sizeof(STU));
    //给空间赋值
    *pi = tmp;
    pi->next = NULL;
    //判断链表是否存在
    if(NULL == head)//空
    {
        head = pi;
        //return head;
    }
    else//非空
    {
        pi->next = head;
        head = pi;
        //return head;
    }
    return head;
}

尾部之后插入节点

//尾部插入节点
STU* insert_link(STU *head, STU tmp)
{
    //为插入的节点申请空间
    STU *pi = (STU *)calloc(1,sizeof(STU));
    //给空间赋值
    *pi = tmp;
    pi->next = NULL;
    //判断链表是否存在
    if(NULL == head)
    {
        head = pi;
        return head;
    }
    else
    {
        //寻找尾部节点
        STU *pb = head;
        while(pb->next != NULL)
            pb = pb->next;
        //将pi插入到 尾节点后
        pb->next = pi;
        return head;
    }
    return head;
}

有序插入节点

//有序插入节点
STU* insert_link(STU *head, STU tmp)
{
    //为插入的节点申请空间
    STU *pi = (STU *)calloc(1,sizeof(STU));
    //给空间赋值
    *pi = tmp;
    pi->next = NULL;
    //判断链表是否存在
    if(NULL == head)
    {
        head = pi;
        return head;
    }
    else
    {
        //寻找插入点
        STU *pf = NULL, *pb = NULL;
        pf = pb = head;
        //从小--->大排序
        while((pb->num < pi->num) && (pb->next != NULL))
        {
            pf = pb;
            pb = pb->next;
        }
        if(pb->num >= pi->num)//头部插入、中部插入
        {
            if(pb == head)//头部插入
            {
                pi->next = head;
                head = pi;
            }
            else//中部插入
            {
                pf->next = pi;
                pi->next = pb;
            }
        }
        else if(pb->next == NULL)//尾部插入
        {
            pb->next = pi;
        }
    }
    return head;
}

2、遍历链表节点

void printf_link(STU *head)
{
    //1、判断链表是否存在
    if(NULL == head)
    {
        printf("链表不存在\n");
        return;
    }
    else//2、链表存在,逐个节点遍历链表
    {
        STU *pb = head;
        while(pb != NULL)
        {
            printf("%d %s %f\n", pb->num, pb->name, pb->score);
            //pb指向下一个节点
            pb = pb->next;
        }
    }
    return;
}

3、查询指定节点

STU *search_link(STU *head, char *name)
{
    //判断链表是否存在
    if(NULL == head)
    {
        printf("链表不存在\n");
        return NULL;
    }
    else//链表存在
    {
        //逐个节点查询
        STU *pb = head;
        while((strcmp(pb->name, name) != 0) && (pb->next != NULL))
        {
            pb = pb->next;
        }
        if(strcmp(pb->name, name) == 0)//找到
            return pb;
        else
        {
            printf("未找到相关节点信息\n");
            return NULL;
        }
    }
    return NULL;
}

4、删除指定节点

STU* delete_link(STU *head, char *name)
 {
     //判断链表是否存在
    if(NULL == head)
    {
        printf("链表不存在\n");
        return head;
    }
    else
    {
        STU *pf =NULL, *pb=NULL;
        pf = pb = head;
        //寻找删除点
        while((strcmp(pb->name, name) != 0) && (pb->next != NULL))
        {
            pf = pb;
            pb = pb->next;
        }
        //找到删除点
        if(strcmp(pb->name, name) == 0)
        {
            if(head == pb)//头部删除
            {
                head= head->next;
            }
            else//中尾部删除
            {
                pf->next = pb->next;
            }
            //释放pb
            if(pb != NULL)
            {
                free(pb);
                pb=NULL;
            }
        }
        else//未找到删除点
        {
            printf("未找到删除的相关节点信息\n");
        }
    }
    return head;
 }

5、释放链表

STU* free_link(STU *head)
 {
    //判断链表是否存在
    if(NULL == head)
    {
        printf("链表不存在\n");
        return head;
    }
    else//链表存在
    {
        STU *pb = head;
        while(pb != NULL)
        {
            //head纪录下一个节点的位置
            head = head->next;
            //释放pb指向的节点
            if(pb != NULL)
            {
                free(pb);
                pb = NULL;
            }
            //pb指向下一个节点
            pb=head;
        }
        printf("链表节点已经完全释放\n");
    }
    return head;
 }

6、链表的翻转

STU* reverse_link(STU *head)
 {
    //判断链表是否存在
    if(NULL == head)
    {
        printf("链表不存在\n");
        return head;
    }
    else
    {
        STU *pb = head->next;
        STU *pn = NULL;
        //将头结点指针域指向NULL
        head->next = NULL;
        //逐个节点翻转
        while(pb != NULL)
        {
            //pn纪录pb->next的节点
            pn = pb->next;
            //进行反向连接
            pb->next = head;
            //移动head到pb上
            head = pb;
            //pb指向pb的节点
            pb = pn;
        }
    }
    return head;
 }

7、链表的排序

//选择法对链表排序
 void sort_link(STU *head)
 {
    //判断链表是否存在
    if(NULL == head)
    {
        printf("链表不存在\n");
        return;
    }
    else
    {
        STU *p_i = head, *p_j = head;//int i=0, j=0;
        while(p_i->next != NULL)//for(i=0;i<n-1; i++)
        {
            STU *p_min = p_i;//int min = i;
            p_j = p_min->next;//j=min+1
            while(p_j != NULL)//j<n
            {
                if(p_min->num > p_j->num)//if(arr[min] > arr[j])
                    p_min = p_j;//min = j;
                p_j = p_j->next;//j++
            }
            if(p_i != p_min)//if(i != min)
            {
                //整体交换
                STU tmp = *p_i;
                *p_i = *p_min;
                *p_min = tmp;
                //指针域交换
                tmp.next = p_i->next;
                p_i->next = p_min->next;
                p_min->next = tmp.next;
            }
            p_i = p_i->next;//i++
        }
    }
    return;
 }

到此这篇关于C++深入分析讲解链表的文章就介绍到这了,更多相关C++链表内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

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

    目录 一.单链表的定义 二.单链表的基本操作的实现 1.初始化 2.取值 3.查找 4.插入 5.删除 三.完整代码 四.测试一下代码 一.单链表的定义 线性表的链式存储又称为单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素.为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针. 单链表中结点类型的描述如下: typedef struct LNode{ // 定义单链表节点类型 ElemType data; // 数据域 struct

  • C++数据结构之双向链表

    本文实例为大家分享了C++数据结构之双向链表的具体代码,供大家参考,具体内容如下 #include <iostream> using std::cout; using std::endl; struct Node {     int data;     struct Node * next;     struct Node * pre; }; 一.创建双向链表 Node * createList() {     Node * head = new Node;     if (NULL == h

  • C++超详细分析单链表的实现与常见接口

    相信如果看完了上期顺序表的小伙伴应该发现了顺序表的诸多缺点:

  • C++ 数据结构超详细讲解单链表

    目录 前言 一.链表是什么 链表的分类 二.链表的实现 总结 (❁´◡`❁) 单链表 前言 上篇顺序表结尾了解了顺序表的诸多缺点,链表的特性很好的解决了这些问题,本期我们来认识单链表. 一.链表是什么 链表是一种物理存储结构上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接依次实现的. 由图,链式结构在逻辑上是连续的,但是物理上不一定连续 显示中结点一般是从堆上申请出来的 从堆上申请的空间,是按照一定的策略划分的,两次申请的空间,可能连续,可能不连续,见顺序表 链表的分类 链表

  • C++零基础精通数据结构之带头双向循环链表

    目录 与单链表的区别 代码的实现 接口 节点的构造 初始化链表 开辟节点 销毁链表 打印链表 尾插链表 尾删链表 头插链表 头删链表 查找链表 链表pos位置的删除 总结 与单链表的区别 单向/双向 单向:只有一个next指针,只指向下一位元素 双向:有两个指针,指向上一位和下一位元素,寻找前一节点和后一节点很便利 带头/不带头 带头:在本来的头结点之前还有一个哨兵卫节点作为头节点,它的址域指针指向头节点,值域不做使用 不带头:没有哨兵卫头节点,在尾删尾插等问题中要考虑头结点的情况(局限) 循环

  • C++基于单链表实现学生成绩管理系统

    本文实例为大家分享了C++实现学生成绩管理系统的具体代码,供大家参考,具体内容如下 /*程序说明:     程序是由单链表实现的学生成绩管理系统,主要功能有输入/查找/删除/修改/排序/显示学生成绩;     输入功能由带头结点的单链表实现,并且使用前插法输入学生信息;     输入功能可以实现插入学生信息的功能,所以无需再专门写一个插入的函数;     删除/修改学生信息要用到查找功能,所以将查找与删除/修改功能写到一起;     查找功能使用顺序查找遍历整个单链表;     使用直接插入法对

  • C++代码实现双向链表

    本文实例为大家分享了C++实现双向链表的具体代码,供大家参考,具体内容如下 双向链表:两个指针域,一个指向前结点,一个指向后结点 list.h #pragma once #define OK         1 #define ERROR     0 #define TRUE     1 #define FALSE     0 typedef int Status; typedef int ElemType; typedef struct DNode {     struct DNode *pr

  • C++超详细讲解单链表的实现

    目录 单链表的实现(从入门到熟练) 概念和结构 链表的实现 增删查改接口 节点结构体创建 节点开辟 数据打印 链表尾插数据 头删 链表数据查找 链表pos位置前插数据 链表pos位置后插数据 链表pos位置数据删除 链表节点释放 链表与顺序表区别 链表的优缺点 顺序表的优缺点 单链表的实现(从入门到熟练) 概念和结构 概念:链表是一种物理存储结构上非连续.非顺序的存储结构 数据元素的逻辑顺序是通过链表中的指针链 接次序实现的 图示: 注意: 链表结构在逻辑上为连续的,但是物理上(内存中)不一定连

  • C++链表类的封装详情介绍

    目录 1.CList.h 2.CList.cpp 3.main.cpp 1.CList.h #ifndef CLIST_H #define CLIST_H   class CNode         //节点类 { public:     CNode();     ~CNode();     void *data;     //数据域  节点数据的地址     CNode *pnext;   //指针域  保存下一个节点的地址 protected: private: };   class CLi

  • C++深入分析讲解链表

    链表的概述 1.数组特点 1.空间连续.元素类型相同.通过下标快速访问 2.静态数组:空间一旦确定不能更改(动态数组除外) 3.静态.动态数组 插入删除元素 需要移动大量数据 2.链表的概述 链表是一种物理存储上非连续,数据元素的逻辑连续通过链表节点中的指针变量保存下个节点的地址,实现的一种线性存储结构. 3.链表的特点 链表由一系列节点(链表中每一个元素称为节点)组成,节点在运行时动态生成(malloc,calloc),每个节点包 括两个部分: 数据域:存放节点数据(核心) 指针域:结构体指针

  • Python字典高级用法深入分析讲解

    目录 一. collections 中 defaultdict 的使用 1.字典的键映射多个值 2.统计字典中某个值出现的次数 二.collections 创建有序字典 1.改变 key-value 的顺序 2.删除 key_value 三.字典排序 1.按照 key 进行排序 2.按照 value 进行排序 四.通过某个关键字排序一个字典列表 一. collections 中 defaultdict 的使用 1.字典的键映射多个值 将下面的列表转成字典 l = [('a',2),('b',3)

  • Java HashMap源码深入分析讲解

    1.HashMap是数组+链表(红黑树)的数据结构. 数组用来存放HashMap的Key,链表.红黑树用来存放HashMap的value. 2.HashMap大小的确定: 1) HashMap的初始大小是16,在下面的源码分析中会看到. 2)如果创建时给定大小,HashMap会通过计算得到1.2.4.8.16.32.64....这样的二进制位作为HashMap数组的大小. //如何做到的呢?通过右移和或运算,最终n = xxx11111.n+1 = xx100000,2的n次方,即为数组大小 s

  • C++深入分析讲解智能指针

    目录 1.简介 2.unique_ptr指针(独占指针) 3.shared_ptr指针(共享所有权) 4.weak_ptr(辅助作用) 5.自实现初级版智能指针 6.总结 1.简介 程序运行时存在静态空间.栈和堆区,用堆来存储动态分配空间的对象即那些在程序运行时分配空间的对象,若该对象不再使用,我们必须显式的销毁它们,避免内存泄漏. 智能指针是一个可以像指针一样工作的对象,有unique_ptr(独占指针),shared_ptr与weak_ptr等智能指针,定义在<memory>头文件中,可以

  • Java开发深入分析讲解二叉树的递归和非递归遍历方法

    目录 前言 1.递归遍历 2.非迭代遍历 3.二叉树的统一迭代法 前言 二叉树的遍历方法分为前序遍历,中序遍历,后续遍历,层序遍历. 1.递归遍历 对于递归,就不得不说递归三要素:以前序遍历为例 递归入参参数和返回值 因为要打印出前序遍历节点的数值,所以参数里需要传入List在放节点的数值,除了这一点就不需要在处理什么数据了也不需要有返回值,所以递归函数返回类型就是void,代码如下: public void preorder(TreeNode root, List<Integer> resu

  • C++深入分析讲解函数与重载知识点

    目录 函数的默认(缺省)参数 1.默认参数的定义 2.默认参数的注意点 占位参数 1.占位参数 函数内部无法使用 2.占位参数 可以设置成缺省参数 函数重载 函数的默认(缺省)参数 1.默认参数的定义 c++在声明函数原型的时可为一个或者多个参数指定默认(缺省)的参数值,当函数调用的时候如果没有传递该参数值,编译器会自动用默认值代替. //函数的默认参数 指定x的默认值为10 y为20 int my_add(int x=10,int y=20) { return x+y; } void test

  • C++深入分析讲解类的知识点

    目录 知识点引入 类的初识 1.封装 2.权限 3.类的定义(定义类型) 4.类的成员函数与类中声明及类外定义 Person类的设计 设计立方体类 点Point和圆Circle的关系 知识点引入 C语言中 数据 和 方法 是独立: //c语言的思想:数据 方法 分开 //人 typedef struct { char name[32]; int age; }Person; //动物 typedef struct { char name[32]; int age; int type; }Dog;

  • Spring Boot深入分析讲解日期时间处理

    目录 GET请求及POST表单日期时间字符串格式转换 使用自定义参数转换器(Converter) 使用Spring注解 使用ControllerAdvice配合initBinder JSON入参及返回值全局处理 修改 application.yml 文件 利用Jackson的JSON序列化和反序列化 总结 GET请求及POST表单日期时间字符串格式转换 这种情况要和时间作为Json字符串时区别对待,因为前端json转后端pojo底层使用的是Json序列化Jackson工具(HttpMessgeC

  • Java深入分析讲解反射机制

    目录 反射的概述 获取Class对象的三种方式 通过反射机制获取类的属性 通过反射机制访问Java对象的属性 反射机制与属性配置文件的配合使用 资源绑定器 配合使用样例 通过反射机制获取类中方法 通过反射机制调用Java对象的方法 通过反射机制获取类中的构造方法 通过反射机制创建对象(调用构造方法) 通过反射机制获取一个类的父类和父接口 反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的

  • C语言深入讲解链表的使用

    目录 一.链表的概念 二.链表的分类 1. 单向或者双向链表 2. 带头或者不带头(是否有自带哨兵位头结点) 3. 循环或者非循环链表 4. 无头单向非循环链表和带头双向循环链表 3.链表的实现(代码和注释) 4.链表oj题(小试牛刀) 总结 现实生活中的火车就像一个完整的链表,现在我们来深入理解一下链表这个数据结构. 一.链表的概念 概念:链表是一种物理存储结构上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链 接次序实现的 . 注: 1.从上图中可看出,链式结构在逻辑上是连续

随机推荐