朝花夕拾 · 数据结构 | 链表篇

朝花夕拾:回顾我的C语言课程设计-学籍管理系统 本文回顾了我在大学期间进行的一个C语言课程设计项目——学籍管理系统。该系统利用C语言的数据结构与算法知识,实现了一个基于命令行的学生信息管理程序。 阅读详情

一.逻辑结构与存储结构

1.数据的逻辑结构

2.数据的存储结构

顺序存储与链式存储的区别:

顺序存储:

1.需要占用内存相邻一块连续的空间,若开辟空间较大时,则可能挤占其余内存空间,产生部分内存外部碎片。

2.由于是顺序存储,元素之间可连续读取,适合查改,效率高;但不适合增删,对顺序存储结构进行增删需遍历数组,将部分元素进行移动。

3.需要进行预分配内存,由于先分配后使用,所以申请空间可能大可能小,造成内存浪费或数组越界。

链式存储:

1.不要求逻辑上相邻的元素在物理上也相邻,可借助元素的后继指针连接,可以充分利用内存空间,不会出现内存碎片现象。

2.由于不要求物理上连续,所以每个元素需要指针来指向后一个元素,增加了内存的消耗。

3.与顺序存储相反,链式存储适合增删,对于元素的位置,只需修改前驱与后继的指针即可;而不适合查改,每次遍历都只能从头指针开始向后遍历整个链表,也可采用双向链表或循环链表进行优化。

4.不需要进行预分配内存,每次使用时动态开辟空间即可,即用即存,不需要时可及时释放内存空间。

注意:线性表是一种逻辑结构,表示元素之间一对一的相邻关系。顺序表和链表是指存储结构,两者属于不同层面的概念,因此不要将其混淆。

二.链表

1.链表的定义

        线性表的链式存储也称单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。单链表结点结构如图2.3所示,其中data为数据域,存放数据元素;next为指针域,存放其后继结点的地址。

typedef struct Node    //定义结点结构
{
    int data;
    struct Node *pnext;
}Node;

typedef struct         //定义链表结构
{
    int len;
    Node *phead;
}Link;

2.三种链表结构

通常用头指针来标识一个单链表,指出链表的起始地址,头指针为NULL时表示一个空表。此外,为了操作上的方便,在单链表第一个数据结点之前附加一个结点,称为头结点。头结点的数据域可以不设任何信息,但也可以记录表长等信息。单链表带头结点时,头指针指向头结点,如图(a)所示。单链表不带头结点时,头指针L指向第一个数据结点,如图(b)所示。表尾结点的指针域为NULL(用“^”表示)。带头结点的链表代码操作较为简单且规范,故推荐定义链表时采用带头结点的方式。

以下有三种链表结构的创建与初始化:

无Link容器的带头结点:

Node * create_link()
{
    Node *phead = malloc(sizeof(Node));
    if(NULL==phead)
    {
        printf("malloc error\n");
        return NULL;
    }
    phead->pnext=NULL;
    phead->data=0;    //头结点data为无效值
    return phead;
}
    

Link容器的带头结点:

Link * create_link()
{
    Link *plink = malloc(sizeof(Link));
    if(NULL==plink)
    {
        printf("malloc error\n");
        return NULL;
    }
    Node *head = malloc(sizeof(Node));
    if(NULL == head)
    {
        printf("mallochead error\n");
        return NULL;
    }
    head->data=0;   //头结点可不赋值
    head->pnext=NULL;

    plink->len=0;
    plink->phead=head;
    return plink;
}

Link容器的不带头结点:

Link *create_link()        //不带头结点,通过Link管理链表,是否带头结点主要看链表有无空结点
{
    Link *plink = malloc(sizeof(Link));
    if (NULL == plink)
    {
        printf("malloc error\n");
        return NULL;
    }
    plink->phead = NULL;
    plink->len = 0;

    return plink;
}

头结点和头指针的关系:

        不管带不带头结点,头指针都始终指向链表的第一个结点,而头结点是带头结点的链表中的第一个结点,结点内通常不存储信息。
        引入头结点后,可以带来两个优点:
        1.第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置上的操作一致,无须进行特殊处理。
        2.无论链表是否为空,其头指针都是指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也就得到了统一。

内存布局:

以下为三种常见链表结构:

3.基本功能实现

以下为不带头结点的链表相关基础功能:

int insert_link_head(Link_t *plink, int data)    //头插
{
    Node_t *pinsert = malloc(sizeof(Node_t));
    if (NULL == pinsert)
    {
        printf("malloc error\n");
        return -1;
    }

    pinsert->data = data;
    pinsert->pnext = NULL;

    pinsert->pnext = plink->phead;
    plink->phead = pinsert;

    plink->clen++;

    return 0;
}

void show_link(Link_t *plink)                //遍历
{
    Node_t *ptmp = plink->phead;

    while (ptmp != NULL)
    {
        printf("%d ", ptmp->data);
        ptmp = ptmp->pnext;
    }
    printf("\n");
}

int is_empty_link(Link_t *plink)             //判空
{
    if (NULL == plink->phead)
    {
        return 1;
    }
    return 0;
}
int insert_link_tail(Link_t *plink, int data)    //尾插
{
    Node_t *pinsert = malloc(sizeof(Node_t));
    if (NULL == pinsert)
    {
        printf("mallocc error\n");
        return -1;
    }
    pinsert->data = data;
    pinsert->pnext = NULL;

    if (is_empty_link(plink))
    {
        plink->phead = pinsert;
    }
    else
    {
        Node_t *ptmp = plink->phead;
        while (ptmp->pnext != NULL)
        {
            ptmp = ptmp->pnext;
        }
        ptmp->pnext = pinsert;
    }
    plink->clen++;

    return 0;
}
int delete_link_head(Link_t *plink)        //头删
{
    if (is_empty_link(plink))
    {
        return -1;
    }

    Node_t *pfree = plink->phead;
    plink->phead = pfree->pnext;
    free(pfree);
    plink->clen--;

    return 0;
}

int delete_link_tail(Link_t *plink)        //尾删
{
    if (is_empty_link(plink))
    {
        return -1;
    }
    else if (NULL == plink->phead->pnext)
    {
        free(plink->phead);
        plink->phead = NULL;
    }
    else
    {
        Node_t *ptmp = plink->phead;
        while (ptmp->pnext->pnext != NULL)
        {
            ptmp = ptmp->pnext;
        }
        free(ptmp->pnext);
        ptmp->pnext = NULL;
    }
    plink->clen--;

    return 0;
}

void destroy_link(Link_t *plink)        //销毁
{
    while (!is_empty_link(plink))
    {
        delete_link_head(plink);
    }
    free(plink);
}

4.内存泄漏

内存泄露:

用户自己申请的堆区空间使用完没有及时释放则造成内存泄露。

检测程序有没有内存泄露:

valgrind:内存错误检测工具(GNU提供),可以检测程序运行过程中的内存泄露情况,以及野指针的使用情况等。

使用方法:

安装valgrind工具:

sudo apt-get isntall valgrind

编译完程序后使用:
valgrind ./a.out
valgrind --leak-check=full ./a.out 

==6742== HEAP SUMMARY:
==6742==     in use at exit: 112 bytes in 7 blocks
==6742==   total heap usage: 10 allocs, 3 frees, 1,168 bytes allocated
==6742== 
==6742== LEAK SUMMARY:
==6742==    definitely lost: 16 bytes in 1 blocks
==6742==    indirectly lost: 96 bytes in 6 blocks
==6742==      possibly lost: 0 bytes in 0 blocks
==6742==    still reachable: 0 bytes in 0 blocks
==6742==         suppressed: 0 bytes in 0 blocks
==6742== Rerun with --leak-check=full to see details of leaked memory

5.快慢指针

逆序、排序思想

    Node_t *ptmp = plink->phead->pnext;
    Node_t *pinsert = NULL;
    plink->phead->pnext = NULL;        //从第二个结点断开

    while()
    {
        pinsert = ptmp;                 //快慢指针
        ptmp = ptmp->pnext;  
        ......
    }       

6.循环链表

 void goto_loop_link(Link_t *plink)
 {
    if (is_empty_link(plink))
    {
        return ;
    }
    Node_t *ptmp = plink->phead;
    while (ptmp->pnext != NULL)
    {
        ptmp = ptmp->pnext;
    }
    ptmp->pnext = plink->phead;
 }
  • 单向链表判断是否有环:

使用快慢指针法:从起点开始,快指针一次走两步,慢指针一次走一步,若快指针最终走到了NULL的位置,说明链表无环;如果快指针和满指针相遇了,则说明有环。

int is_loop_link(Link_t *plink)
 {
    Node_t *pfast = plink->phead;
    Node_t *pslow = pfast;

    while (pfast != NULL)
    {
        pfast = pfast->pnext;
        if (NULL == pfast)
        {
            return 0;
        }
        if (pfast == pslow)
        {
            return 1;
        }
        pfast = pfast->pnext;
        pslow = pslow->pnext;
        if (pfast == pslow)
        {
            return 1;
        }
    }

    return 0;
 }
  • 有环链表的环长:

从相遇点开始,让指针开始遍历链表,当该指针再次走到相遇点,则统计出了的个数为环长。

  • 求有环链表环的入口:

经过推算,相遇点到环入口长度等于开头到环入口的位置。一个指针从想遇点开始走,一个指针从头走,当两个指针再次相遇,则为环形的入口。

Node_t *get_loop_enter(Link_t *plink)
{
    if (NULL == plink->phead)
    {
        return NULL;
    }

    Node_t *pfast = plink->phead;
    Node_t *pslow = pfast;

    while (1)
    {
        pfast = pfast->pnext;
        if (pfast == pslow)
        {
            break;
        }
        pfast = pfast->pnext;
        pslow = pslow->pnext;
        if (pfast == pslow)
        {
            break;
        }
    }

    pslow = plink->phead;
    pfast = pfast->pnext;
    while (pslow != pfast)
    {
        pfast = pfast->pnext;
        pslow = pslow->pnext;
    }

    return pslow;
}

7.双链表

Link_t* create()
{
    Link_t *plink = malloc(sizeof(Link_t));
    if(NULL == plink)
    {
        printf("malloc errorlink\n");
        return NULL; 
    }
    plink->phead = NULL;
    plink->clen = 0;
    return plink;
}

int isempty(Link_t *plink)
{
    return plink && NULL == plink->phead;
}

int insert_head(Link_t *plink,Stu_t t)
{
    Node_t *pnode = malloc(sizeof(Node_t));
    if(NULL == pnode)
    {
        printf("malloc errorinsert\n");
        return -1;
    }
    pnode->t = t;
    pnode->pnext = NULL;
    pnode->ppre = NULL;
    if(isempty(plink))
    {
        plink->phead = pnode;
    }
    else
    {
        pnode->pnext = plink->phead;
        plink->phead->ppre = pnode;
        plink->phead = pnode;
    }
    plink->clen++;
    return 0;
}
int insert_tail(Link_t *plink,Stu_t t)
{
    Node_t *pnode = malloc(sizeof(Node_t));
    if(NULL == pnode)
    {
        printf("malloc errorinsert\n");
        return -1;
    }
    pnode->t = t;
    pnode->pnext = NULL;
    pnode->ppre = NULL;
    if(isempty(plink))
    {
        plink->phead = pnode;
    }
    else
    {
        Node_t *ptmp = plink->phead;
        while(ptmp->pnext!= NULL)
        {
            ptmp = ptmp->pnext;
        }
        ptmp->pnext = pnode;
        pnode->ppre = ptmp;
    }
    plink->clen++;
    return 0;

}
void delete_head(Link_t *plink)
{
    if(isempty(plink))
    {
        return;
    }
    Node_t *pfree = plink->phead;
    plink->phead = pfree->pnext;
    free(pfree);
    plink->clen--;
    if(!isempty(plink))
    {
     plink->phead->ppre = NULL;
    }
}
void delete_tail(Link_t *plink)
{
    if(isempty(plink))
    {
        return;
    }
    Node_t *ptmp = plink->phead;
    while(ptmp->pnext!=NULL)
    {
        ptmp = ptmp->pnext;
    }
    if(ptmp->ppre)
    ptmp->ppre->pnext = NULL;
    else
    plink->phead = NULL;
    free(ptmp);
    plink->clen--;
}
void print(Link_t *plink,int dir)
{
    if(isempty(plink))
    {
        return;
    }
    Node_t *ptmp = plink->phead;
    if(dir)
    {   
        while(ptmp!=NULL)
        {
            printf("%s %d %d\n",ptmp->t.str,ptmp->t.age,ptmp->t.score);
            ptmp = ptmp->pnext;
        }
    }
    else
    {
        while(ptmp->pnext!=NULL)
        {
            ptmp = ptmp->pnext;
        }
        while(ptmp!=NULL)
        {
            printf("%s %d %d\n",ptmp->t.str,ptmp->t.age,ptmp->t.score);
            ptmp = ptmp->ppre;
        }
    }
    printf("\n");
}
void destroy(Link_t *plink)
{
    // if(isempty(plink))
    // {
    //     return;
    // }
    // Node_t *ptmp = plink->phead;
    // Node_t *pfree = ptmp;
    // while(ptmp!= NULL)
    // {
    //     pfree = ptmp;
    //     ptmp = ptmp->pnext;
    //     free(pfree);       
    // }
    // free(plink);
    while (!isempty(plink))
    {
        delete_head(plink);
    }
    free(plink);
}

8.内核链表

Linux内核中使用到的一种链表形式。
本质:双向循环链表

和普通链表的区别:
1.普通链表将数据存储在结点中,程序中,一但确定了结点中存储得数据得数据类型,该链表再无法存储其他类型的数据。
2.内核链表将结点嵌入到要存储的数据结构体中,在项目工程中,一套链表操作,可以用来存储不同类型的数据。

内核提供宏:
offsetof:获取链表结点首地址到结构体开头的偏移量。
container_of:利用结点的首地址-偏移量,获得结构体首地址。

朝花夕拾:回顾我的数据结构课程设计-基于C/C++/QT一元稀疏多项式计算器 本文回顾了我在大学期间进行的一个数据结构课程设计,要求设计一个一元稀疏多项式的计算器。这对测试我们的数据结构知识有帮助。 阅读详情

相关推荐

[朝花夕拾]单链表篇-C++

朝花夕拾[朝花夕拾]单链表篇-C++单链表结构定义-头文件 singly_list.h测试数据结构定义头文件 student.h源文件 student.cpp简单的测试函数编写-main函数 [朝花夕拾]单链表篇-C++ 本例结合模板对单链表进行了一个简单的C++实现,可为数据结构新手进行学习提供参考,中间可能有考虑不周之处烦请指出,该文章属于作者原创文章,当前时间节点前全网没有第二篇,转载请注明...

知其然而后知其所以然 247

UE游戏引擎材质简单入门

什么是物体的材质,材质属性定义了物体的某些特性,从而决定了物体表面是如何与光线相作用的。UE中物理基础渲染(Physically Based Rendering OR PBR)几乎可以让我们模拟显示世界中的任何材质。那么如何在UE中制作出真实的PBR材质,基于我们提供的游戏引擎插件,如何将这些材质资源导出,并应用到 SuperMap iClient3D for Cesium/WebGL 平台上,提升模型的显示效果呢,下面小编将详细讲解一下。

m0_71055362的博客 2511

朝花夕拾 · 数据结构 | 队列与栈篇

1.队列的定义队列(Qucue)简称队,也是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。向队列中插入元素称为入队或进队;删除元素称为出队或离队。这和我们日常生活中的排队是一致的,最早排队的也是最早离队的,其操作的特性是先进先出(FirstInFirst Out,FIFO),如图所示。队头(Front):允许删除的一端,也称队首。队尾(Rear):允许插入的一端。空队列:不含任何元素的空表。顺序队列的两种定义:1.2.以第一种定义为例,以下为相关CRUD功能实现。

Vvc_Python的博客 463

linux内核学习(八)---摄像头框架移植(上)

本章来开始进行摄像头的移植,同时回顾一下V4L2的整个框架

文艺小少年的博客 113

FPGA入门200例(17):如何阅读RTL原理图(Schematic)?将Verilog代码与门级电路对应

本文针对FPGA开发新手常见误区,重点讲解了RTL原理图的重要性和阅读方法。文章指出,仅通过仿真验证代码会导致板级测试异常,而RTL原理图能直观呈现Verilog代码对应的硬件结构(门电路、寄存器、多路选择器等)。通过"识别基础元件→跟踪信号路径→验证逻辑关系"的三步法,新手可以建立代码与硬件的映射思维,排查冗余逻辑、意外锁存器等错误。文章还结合Vivado/Quartus工具操作指南和典型代码案例,帮助读者掌握从代码到硬件实现的转换过程,避免混淆RTL与门级原理图、忽略信号位宽等常见误

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 200

【朝花夕拾】如何实现一个高效的单向链表逆序输出?

问题:如何实现一个高效的单向链表逆序输出? 出题人:阿里巴巴出题专家:昀龙/阿里云弹性人工智能负责人 参考答案:下面是其中一种写法,也可以有不同的写法,比如递归等。供参考。 typedef struct node{ int data; struct node* next; node(int d):data(d), next(NULL){} }node; void reverse(node* head) { if(head == NULL){

ReganYue's Blog 2903

Claude Code 安装指南(Windows / macOS)

本文介绍了Claude Code的安装准备和基本流程。作为开发者工具,安装前需具备命令行操作能力、可用的Claude账号和稳定网络环境。Windows和macOS的安装都需通过终端完成,安装后以命令行形式运行。首次使用建议在熟悉项目中执行简单任务,逐步建立使用习惯。强调安装只是开始,后续需学习如何有效使用工具,包括任务提交流程和上下文提供方法。核心要点是:Claude Code是开发者工具,网络和终端环境是关键,建议先运行再深入理解。

sg_knight的专栏 4486

朝花夕拾 · 数据结构 | 哈希表篇

在构造散列函数时,必须注意以下几点:1)散列函数的定义域必须包含全部关键字,而值域的范围则依赖于散列表的大小。2)散列函数计算出的地址应尽可能均匀地分布在整个地址空间,尽可能地减少冲突。3)散列函数应尽量简单,能在较短的时间内计算出任意一个关键字对应的散列地址。下面介绍常用的散列函数。代码实现:哈希表的定义。

Vvc_Python的博客 482

智慧城市中的CV:交通流量监控与行人检测

智慧城市中的CV:交通流量监控与行人检测 ,人工智能,计算机视觉,大模型,AI,计算机视觉作为人工智能的重要分支,通过分析和理解图像或视频数据,为智慧城市提供了强大的感知能力。在交通管理领域,计算机视觉技术可实现交通流量监控、行人检测、违章行为识别等功能,助力构建高效、安全、绿色的城市交通系统。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 5万+

饥饿游戏搜索算法(HGS)详解:从生物激励到智能优化

饥饿游戏搜索算法(HGS)是一种受动物饥饿驱动觅食行为启发的智能优化算法。该算法通过模拟生物饥饿程度与觅食策略的关系,将个体适应度映射为饥饿感,并据此动态调整搜索行为。HGS的核心机制包括:1) 饥饿权重计算(W1/W2),2) 三种位置更新策略(随机探索、正向/负向协作),3) 自适应平衡参数E。算法通过迭代优化逐步改进解的质量,具有参数自适应、全局搜索能力强等特点,在复杂优化问题中表现出色。相比传统优化方法,HGS更注重个体内部状态对搜索行为的影响,实现了探索与开发的自然平衡。

qq_42212808的博客 155

JAVA朝花夕拾-集合框架

Collections框架:Collections :List:(当存储相同的元素时不会覆盖,先进先出,可以使用sort排序)ArrayList: 可以使用null,采用数组实现,若不指定大小则初始化大小10,如果使用size()直接输出为0,每次扩容大小为原来的1.5倍,线程不安全,查找时间复杂度为:O(n);get O(1),add() O(1),...

aaabc1112345的博客 354

PCL 建筑物点云立面和平面分割提取【2025最新版】

在建筑物点云中,立面点和平面点的法向量存在明显的差异,根据法向量在Z方向的分量设置相应得阈值即可实现立面点与平面点的分割。

点云侠的博客 1962

【朝花夕拾】2021年最新阿里巴巴面试题 |带参考答案| 汇总(一)

问题:如何实现一个高效的单向链表逆序输出? 出题人:阿里巴巴出题专家:昀龙/阿里云弹性人工智能负责人 参考答案:下面是其中一种写法,也可以有不同的写法,比如递归等。供参考。 typedef struct node{ int data; struct node* next; node(int d):data(d), next(NULL){} }node; void reverse(node* head) { if(head == NULL){ .

ReganYue's Blog 3031

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Java朝花夕拾-非阻塞队列之ConcurrentLinkedQueue

ConcurrentLinkedQueue非阻塞队列 采用先进先出的规则。采用链表实现,由头节点和尾节点组成当插入元素时,不会加锁,因此不会阻塞,当时会有一个死循环,直到插入成功,遍历链表,找到队尾,将元素插入采用cas算法 public boolean offer(E e) { if (e == null) throw ne...

aaabc1112345的博客 134

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

朝花夕拾 - 8月离职 & 9月规划

好像,有一个月没有发公众号,没有接触前端工作相关的东西了,今天谈谈 jsliang 7 月底离职、8 月休息,到今天 9月1日,这一个月的感想。简单来说:吹吹水,聊聊天一 8 月做了啥 ...

weixin_41806099的博客 468

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

c语言实现的单链表及一些基本操作

又是一篇学习记录。 单链表算是很经典的一种数据结构了,记得数据结构课本开篇就讲的它。 可能是因为比较简单吧。结构体代码如下: typedef struct _NODE { int value; struct _NODE* next; }NODE, *PNODE;

roronoa 565

Java朝花夕拾-阻塞队列

BlockingQueue 是java.util.current下主要用来控制线程同步的工具,阻塞型队列,有四种实现类:1,ArrayBlockingQueue 大小规定,先进先出,采用数组实现2,LinkedBlockingQueue 大小不确定,先进先出,采用链表实现3,PriorityBlockingQueue 自然排序,或者是构造函数的Compara...

aaabc1112345的博客 195

温故而知新---1

浅浅地复习一下

少年何妨梦摘星,敢挽桑弓射玉衡。 他时若遂凌云志,敢笑黄巢不丈夫。 209

C++ 复习 01

文章目录STL之容器顺序容器vector 线性连续地址空间deque 双端队列deque 的迭代器关联容器无序关联容器容器适配器STL之算法:std::sort的实现最小分段阈值 _S_threshold = 16STL之空间配置器:1. 标准空间配置器 std::allocator2.特殊的空间配置器 std::alloc对象的构造与析构内存空间的配置与释放第一层配置器 >128 B __ma...

Tattoo的博客 786

【数据结构-5】单链表的实现

单链表,具体来说是单向的、不带头的、不循环的链表。链表由一个一个节点组成,每个节点分为数据域和指针域,数据域存放数据,指针域存放下一节点的地址。这样,就可以根据指针域中的地址找到下一个节点,节点就串起来了构成了单链表。

weixin_44218929的博客 193

pandas 深度入门:从数据结构到一份真实销售报表

本文系统讲解Pandas核心应用,从三分钟安装到完整月度报表生成,涵盖数据读取、清洗、筛选、分组聚合、表连接、透视表与时间序列等13个关键环节。强调“先看数据再动手”,掌握Series/DataFrame/Index结构本质,熟练运用loc/iloc、merge校验、agg/transform区别,通过真实案例实现高效报表自动化,告别手动Excel操作。最后提供性能优化与高频报错解决方案,助力读者快速上手,真正实现“写二十行代码,跑三秒出结果”。

信息安全领域优质创作者|操作系统领域专家 290

数据结构的基本概念和算法的初步认识

本文系统阐述数据结构与算法的基础概念,涵盖数据、数据元素、数据对象的层次关系,数据结构的三要素(逻辑结构、存储结构、数据运算),以及抽象数据类型。重点解析算法的特性与设计要求,并深入讲解时间复杂度分析的核心——大O表示法,通过“只保留最高阶项、忽略常数系数、取最坏情况”三大原则,结合实例剖析O(1)、O(n)等常见时间复杂度,揭示算法效率的本质评估方法。

ACH_YYX的博客 188

数据结构:9.Map和Set

有的讲解会说这里key是标识作用,这种说法其实没有太大意义,就算知道了他是标识value的作用又如何,在实际的使用过程中,我们只会根据具体的效果选择使用的方法等,不会执着于“标识”这种说法。2.由于哈希函数的设计原则太过理论,它仅仅是在认为:这些通过关键码算出来的index不同 的情况下设计的,然而这种理论化的设计原则在遇到冲突时,恰恰就出现了问题,而我们能做的,就是降低冲突率。虽然哈希表的使用过程中存在冲突,但是在实际的使用过程中,哈希表的冲突率是不高的,冲突的个数是可控的。

2602_95646088的博客 204

Vue3 低代码移动表单设计器实战(二):缩放画布下的拖拽系统与树状级联数据结构

本文深入剖析Vue3低代码表单设计器在缩放画布下的拖拽失效问题,揭示SortableJS在CSS Transform下坐标崩溃的数学根源。通过自研独立视觉克隆壳层与逆向几何补偿算法,实现精准拖拽;采用扁平数据存储+运行时树状计算结构,解决级联依赖与深克隆难题,确保逻辑一致性与性能优化,为复杂低代码系统提供可复用的工程范式。

NanChen的博客 343

排序算法深度笔记(上):比较类排序的思想演进与代码实现

与。本文聚焦前者 —— 也就是通过元素间两两比较来确定相对顺序的排序算法,从最朴素的 O (n²) 基础排序,到工业级主流的 O (nlogn) 进阶排序,逐层拆解设计思想、带注释的代码实现与边界细节。当我们理解了比较排序的性能边界,也就自然引出了非比较排序的存在意义。所有代码均遵循统一的实现规范:入口函数前置空数组与单元素边界校验,基于数组原地修改,主函数附带可直接运行的测试用例,与练习代码风格完全对齐。

2401_87069538的博客 626
上一篇: 朝花夕拾 · C语言 | 多文件篇
下一篇: 朝花夕拾 · 数据结构 | 队列与栈篇
剑指offer.
博客等级 码龄3年 15粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值