11.链表

数组的分类:便于遍历

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

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

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

链表的基本概念

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

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

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

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

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

知识点三:静态链表

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)

#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、链表的有序插入

链表有序插入

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

链表查询某个节点

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

删除链表指定节点

知识点七:链表的释放

链表的释放
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;
}

知识点八:链表逆序

链表逆序
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;
}

知识点九:链表排序

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

链表排序
#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

知识点十:认识双向链表

双向链表

知识点十一:双链表插入

双链表插入

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

指针变量作为结构体的成员
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、指针变量作为结构体的成员 操作前 必须有合法空间

指针变量作为结构体的成员1
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、指针变量作为结构体成员,结构体变量间的赋值操作容易导致“浅拷贝”发生

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

运行结果:出现段错误

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

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、深拷贝

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

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

深拷贝
#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;
    }
}

相关推荐

  1. <span style='color:red;'>11</span>.<span style='color:red;'>链</span><span style='color:red;'>表</span>

    11.

    2024-06-10 11:40:03      30 阅读
  2. 问题 B: 实验11_10_排序

    2024-06-10 11:40:03       153 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-10 11:40:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-10 11:40:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-10 11:40:03       82 阅读
  4. Python语言-面向对象

    2024-06-10 11:40:03       91 阅读

热门阅读

  1. 汇川CodeSysPLC教程03-2-3 Modbus ASCII

    2024-06-10 11:40:03       30 阅读
  2. GoogLeNet

    GoogLeNet

    2024-06-10 11:40:03      25 阅读
  3. MySQL和Oracle区别

    2024-06-10 11:40:03       34 阅读
  4. LeetCode 239. 滑动窗口最大值

    2024-06-10 11:40:03       32 阅读
  5. B树、B+树与索引、联合索引

    2024-06-10 11:40:03       31 阅读
  6. 家族企业如何找到合适的人才

    2024-06-10 11:40:03       33 阅读
  7. 捡贝壳问题

    2024-06-10 11:40:03       27 阅读
  8. C#.net MassTransit和DotNetCore.CAP区别

    2024-06-10 11:40:03       31 阅读
  9. 动态规划路径问题(C++)

    2024-06-10 11:40:03       41 阅读
  10. Spring (48)Feign

    2024-06-10 11:40:03       28 阅读