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;
    }
}
相关推荐
湫ccc3 分钟前
Python简介以及解释器安装(保姆级教学)
开发语言·python
程序伍六七6 分钟前
day16
开发语言·c++
wkj00111 分钟前
php操作redis
开发语言·redis·php
极客代码16 分钟前
【Python TensorFlow】进阶指南(续篇三)
开发语言·人工智能·python·深度学习·tensorflow
土豆湿22 分钟前
拥抱极简主义前端开发:NoCss.js 引领无 CSS 编程潮流
开发语言·javascript·css
界面开发小八哥29 分钟前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
jiao_mrswang1 小时前
leetcode-18-四数之和
算法·leetcode·职场和发展
qystca1 小时前
洛谷 B3637 最长上升子序列 C语言 记忆化搜索->‘正序‘dp
c语言·开发语言·算法
薯条不要番茄酱1 小时前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
今天吃饺子1 小时前
2024年SCI一区最新改进优化算法——四参数自适应生长优化器,MATLAB代码免费获取...
开发语言·算法·matlab