11.链表

数组的分类:便于遍历

静态数组:int arr[10]数据过多造成空间溢出,数据过小空间浪费

动态数组:malloc calloc realloc 合理利用空间不能快捷的插入或删除数据(会涉及到大量的数据移动)

知识点一:链表的基本概念

链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构

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

1)存储数据元素的数据域          2)存储下一个节点地址的指针域

知识点二:链表结点的定义(结构体实现)

c 复制代码
typedef struct stu
{
    //数据域(自定义)
    int num;
    char name[32];
    float score;
    //指针域
    struct stu *next;	//保存 下一个节点的地址:
}STU;

知识点三:静态链表

c 复制代码
typedef struct stu
{
    int num;
    char name[32];
    float score;
    struct stu *next;	//保存 下一个节点的地址:
}STU;
void test1()
{    
    STU datal = {100, "德玛",59};
    STU data2 = {101, "小炮",89};
    STU data3 = {102, "小法",79};
    STU data4 = {103,"盲僧",99};
    STU data5 = {104, "快乐风男",39};
    //链表头
    STU *head = NULL;
    head = &datal;
    datal.next = &data2;
    data2.next = &data3;
    data3.next = &data4;
    data4.next = &data5;
    data5.next = NULL;
    //遍历链表
    STU *pb = head;
    while(pb != NULL)
    {
        printf("%d %s %f\n", pb->num, pb->name, pb->score) ;
        pb = pb->next;    //pb指向下一一个节点
    }
}

知识点四:动态链表

1、布局整个框架(main.c)

c 复制代码
#include<stdio.h>
#include<string.h>
void stu_help(void);
int main(int argc,char *argv[])
{
    stu_help();
    while(1)
    {
        printf("请输入操作指令:");
        char cmd[32] = "";
        scanf( "%s",cmd);
        if(strcmp(cmd,"help") == 0)
        {
            printf("-----help------\n");
        }
        else if(strcmp(cmd,"insert") == 0)
        {
            printf("-----insert------\n");
        }
        else if(strcmp(cmd,"print") == 0)
        {
            printf("-----print------\n");
        }
        else if(strcmp(cmd,"search") == 0)
        {
            printf("-----search------\n");
        }
        else if(strcmp(cmd,"delete") == 0)
        {
            printf("-----delete------\n");
        }
        else if(strcmp(cmd,"free") == 0)
        {
            printf("-----free------\n");
        }
        else if(strcmp(cmd,"quit") == 0)
        {
            break;
        }
     }        
    return 0;
}
void stu_help(void)
{
    printf("############################\n");
    printf("#help:打印帮助信息         #\n");
    printf("#insert:插入链表节点       #\n");
    printf("#print:遍历链表节点信息    #\n");
    printf("#search:查询链表节点       #\n");
    printf("#delete:删除链表节点       #\n");
    printf("#free:释放链表             #\n");
    printf("#quit:退出                 #\n");
    printf("############################\n");
    return;
}

2、链表插入节点之头部之前插入

3、在链表尾部插入

4、链表的有序插入

知识点五:链表查询某个节点

知识点六:删除链表指定节点

知识点七:链表的释放

c 复制代码
STU* free_link(STU *head)
{
    //1、判断链表是否存在
    if(head == NULL)//不存在 
    {
        printf("link not found\n");
        retrun head;
    } 
    else	//存在 
    {
        STU *pb = head;
        //逐个节点释放
        while(pb != NULL)
        {
            //head保存下一个节点的位置
            head = pb->next;
            //释放pb指向的节点
            free(pb);
            //pb指向head
            pb = head; 
        }
        printf("链表已经释放完毕\n"); 
        return head;
    }
    return head;
}

知识点八:链表逆序

c 复制代码
STU* reverse_link(STU *head)
{
    //1、判断链表是否存在
    if(head == NULL)//不存在 
    {
        printf("link not found\n");
        retrun head;
    } 
    else//存在 
    {
        //int *p,num;     //p为int *, num为int
        STU *pb,*pr;    //pb为STU *,pr 为STU *
        //pb保存head->next ( 原因head->next会置NULL)
        pb = head->next;
        //将head->next置NULL(原因:头节点变尾节点)
        head->next = NULL;
        while(pb != NULL)
        {
            //pr 保存pb->next ( 原因:pb->next会指向head)
            pr = pb -> next;
            //pb->next指向head ( 原因:逆转方向)
            pb->next = head ;
            //保存逆转方向的代码可以重复执行
            head = pb;
            pb = pr;
        }
        return head;
    }
    return head;
}

知识点九:链表排序

选择法排序:(以数组实现)

c 复制代码
#include<stdio.h>
int main()
{
    int arr[10] = {0};
    int n = sizeof(arr)/sizeof(arr[0]);
    int i = 0,j = 0,min = 0;
    printf("请输入%d个int数据\n", n);
    for(i = 0; i<n; i++)
    {
        scanf("%d",arr+i);
    }
    for(i = 0;i < n-1;i++)
    {
        for(min = i,j = min+1;j < n;j++)
        {
            if (arr[min] > arr[j])
            min = j;
        }
        if (min != i)
        {
            int tmp = 0;
            tmp = arr[i];
            arr[i] = arr[min];
            arr [min] = tmp;
        }
    }
    for(i = 0;i < n;i++) 
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
    return 0;
}

选择法排序:(以链表实现)

知识点十:认识双向链表

知识点十一:双链表插入

知识点十二:双向链表删除指定节点

知识点十三:结构的浅拷贝和深拷贝

1、指针变量作为结构体的成员

c 复制代码
typedef struct
{
    int num;
    char *name;//指针变量作为结构体的成员
}DATA;
void test01()
{
    DATA data = {100, "hehehehaha"};
    printf("%d\n",sizeof(DATA));//8字节
    printf("num = %d\n" ,data.num) ;
    //指针变量作为结构体的成员保存的是空间的地址
    printf("name = %s\n", data. name);
}

2、指针变量作为结构体的成员 操作前 必须有合法空间

c 复制代码
void test02()
{
    DATA data;
    printf( "%d\n",sizeof(DATA));
    printf("num = %d\n", data.num) ;
    //指针变量作为结构体的成员操作前必须有合法的空间
    //data.name = "hehe" ;
    //给name事先申请一块堆区空间
    data.name = (char *)calloc(1,10);
    strcpy(data.name,"hahaha");
    printf("name = %s\n", data.name ) ;
    //如果name指向堆区空间一定要记得释放
    if(data. name != NULL )
    {
        free(data. name) ;
        data. name = NULL;
    }
}

3、指针变量作为结构体成员,结构体变量间的赋值操作容易导致"浅拷贝"发生

运行结果:出现段错误

两个结构体变量中的指针成员指向同-块堆区空间

c 复制代码
void test03()
{
    DATA data1;
    DATA data2;
    data1.num = 100;
    data1.name = (char *)calloc(1,10);
    strcpy(data1.name,"my data");
    //指针变量作为结构体的成员结构体变量间的赋值操作容易导致"浅拷贝"发生
    data2 = data1;    //"浅拷贝"
    printf("data2: num = %d,name = %s\n", data2.num,data2.name); 
     if(datal.name != NULL)
    {
        free(data1.name);
        data1.name = NULL;
    }
    if( data2.name != NULL)
    {
        free(data2.name);
        data2.name = NULL;
    }
}

4、深拷贝

前提:是指针变量作为结构体的成员

两个结构体变量中的指针成员指向各自的堆区空间

c 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct
{
    int num;
    char *name;
} DATA;
void test01()
{
    DATA datal ;
    DATA data2 ;
    datal.num = 100;
    datal.name = (char *)calloc(1,12);
    strcpy (datal.name,"my data");
    data2. num = datal. num;
    //为结构体变量 申请 独立空间 
    data2.name = (char *)calloc(1,12);
    strcpy(data2.name,datal.name) ;
    printf("data1:num = %d,name = %s\n",datal.num,datal.name);
    printf("data2:num = %d,name = %s\n",data2.num,data2.name);
    if (datal.name!=NULL)
    {
        free(datal.name);
        datal.name = NULL;
    }
    if (data2.name!=NULL)
    {
        free(data2.name);
        data2.name = NULL;
    }
}
相关推荐
南城花随雪。4 分钟前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
dundunmm19 分钟前
机器学习之scikit-learn(简称 sklearn)
python·算法·机器学习·scikit-learn·sklearn·分类算法
古希腊掌管学习的神20 分钟前
[机器学习]sklearn入门指南(1)
人工智能·python·算法·机器学习·sklearn
波音彬要多做21 分钟前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
Swift社区29 分钟前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
Noah_aa31 分钟前
代码随想录算法训练营第五十六天 | 图 | 拓扑排序(BFS)
数据结构
一道微光33 分钟前
Mac的M2芯片运行lightgbm报错,其他python包可用,x86_x64架构运行
开发语言·python·macos
矛取矛求37 分钟前
QT的前景与互联网岗位发展
开发语言·qt
Leventure_轩先生37 分钟前
[WASAPI]从Qt MultipleMedia来看WASAPI
开发语言·qt
向宇it1 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎