数据结构-链表

一.数据结构

1.1 什么叫数据结构

**数据结构:**一组用来保存一种或多种特定关系的数据集合(组织和存储数据)。

程序设计 = 数据结构 + 算法

1.2 数据与数据之间的关系

1.2.1 逻辑结构:

数据元素与元素之间的关系

1、集合:平等关系

2、线性结构:元素与元素之间一对一的关系(顺序表,链表,队列、栈)

3、树形结构:元素与元素之间一对多的关系(二叉树)

4、图形结构:元素与元素之间多对多的关系(图)

1.2.2 物理结构:

数据元素在计算机内存中的存储方式

1、顺序结构:选用一段连续的内存空间

比如:数组

  1. 数据访问方便(O(1))

  2. 元素插入和删除需要移动大量数据,效率低

  3. 预分配内存空间

2、链式结构:选用非连续的内存空间

比如:链表

  1. 数据访问需要遍历(O(n))

  2. 插入和删除元素方便

  3. 不需要预分配,可以动态存储

  4. 可以有效利用内存碎片(内存碎片:一些游离的小的内存空间)

3、散列结构(哈希结构):将要存储的数据的关键字存储位置之间构建映射关系(哈希函数)存储和查找都根据映射关系查找,为了提高数据的查找效率。

4、索引存储:通关索引表寻找数据的存储位置,为了提高数据的查找效率。

二. 单向链表

2.1 单向链表结构

2.2 单向链表实现

cpp 复制代码
//链表节点结构体
typedef struct linknode{
    DATATYPE_T data;//数据域
    struct linknode *pnext;//指针域
}Node_t;

//链表对象结构体
typedef struct link{
    Node_t *phead;//存储头节点
    int clen;//链表节点个数
}Link_t;

这里Node_t 与 Link_t 中 _t 的含义:_ttype 的缩写,意思是:这是一个通过 typedef 定义的

【类型别名】,不是原生类型。

2.3 创建链表对象

cpp 复制代码
//创建链表对象
Link_t *creat_link()
{
    Link_t *plink = malloc(sizeof(Link_t));
    if(plink == NULL)
    {
        printf("malloc error!\n");
        return NULL;
    }
    plink->phead = NULL;
    plink->clen = 0;
    return plink;
}

2.4 创建链表新节点

cpp 复制代码
//创建链表新节点
Node_t *creat_node(DATATYPE_T x)
{
    Node_t *pnode = malloc(sizeof(Node_t));
    if(pnode == NULL)
    {
        printf("malloc error!\n");
        return NULL;
    }
    pnode->data = x;
    pnode->pnext = NULL;
    return pnode;
}

2.5 链表判空

cpp 复制代码
bool is_empty_link(Link_t *plink)
{
    return plink->clen == 0;
}

2.6 链表头插

cpp 复制代码
//链表头插
int insert_link_head(Link_t *plink, DATATYPE_T data)
{

    Node_t *pnewnode = creat_node(data);
    if(pnewnode == NULL)
        return -1;

    pnewnode->pnext = plink->phead;
    plink->phead = pnewnode;
    plink->clen++;
    return 0;
}

2.7 链表头删

保存原头节点

cpp 复制代码
//链表头删
int delete_link_head(Link_t *plink)
{
    if(is_empty_link(plink))
        return 0;
    else
    {
        Node_t *pfree = plink->phead;//保存原头节点
        plink->phead = pfree->pnext;
        plink->clen--;
        free(pfree);
        pfree = NULL;
        return 0;
    }
}

2.8 链表尾插

注意:这里找尾节点是对ptail->pnext 进行循环判断

cpp 复制代码
//链表尾插
int insert_link_tail(Link_t *plink, DATATYPE_T data)
{
    Node_t *pnewnode = creat_node(data);//创建新节点
    if(pnewnode == NULL)
        return -1;
    Node_t *ptail = plink->phead;
    if(is_empty_link(plink))//表示链表为空
    {
        plink->phead = pnewnode;
        plink->clen++;
        return 0;
    }
    while(ptail->pnext)//开始找尾节点
    {
        ptail = ptail->pnext;
    }
    ptail->pnext = pnewnode;//连接新节点
    plink->clen++;
    return 0;
}

2.9 链表尾删

注意:链表尾删要分三种情况:空链表,只有一个节点,一个以上节点。

cpp 复制代码
//链表尾删
int delete_link_tail(Link_t *plink)
{
    if(is_empty_link(plink))//链表为空
        return 0;
    else if(plink->phead->pnext == NULL)//链表只有一个节点
    {
        delete_link_head(plink);
        return 0;
    }
    //一个以上节点
    else
    {
        Node_t *ptail = plink->phead, *prev = NULL;
        while(ptail->pnext)
        {
            prev = ptail;
            ptail = ptail->pnext;
        }
        prev->pnext = NULL;
        free(ptail);
        ptail = NULL;
        plink->clen--;
        return 0;
    }
}

2.10 链表打印

cpp 复制代码
//打印链表
void print_link(Link_t *plink)
{
    Node_t *cur = plink->phead;
    while(cur)
    {
        printf("%d->",cur->data);
        cur = cur->pnext;
    }
    printf("NULL\n");
}

2.11 链表销毁

cpp 复制代码
//销毁链表
void destroy_link(Link_t *plink)
{
    while(!is_empty_link(plink))
    {
        delete_link_head(plink);
    }
    free(plink);
}

三. valgrind工具

3.1 简介

Valgrind 是 Linux GNU提供的一个内存错误检查软件 ,核心用途是内存调试内存泄漏检测线程错误检测性能分析。在程序运行过程中检查内存错误。

3.2 安装方法

使用命令:

bash 复制代码
sudo apt-get install valgrind

3.3 使用方法

++valgrind ./可执行程序++

执行结果:

cpp 复制代码
==3101== 
==3101== HEAP SUMMARY:  //堆内存使用总结
==3101==     in use at exit: 96 bytes in 6 blocks //程序退出时还有96字节,6块内存没释放
==3101==   total heap usage: 7 allocs, 1 frees, 1,120 bytes allocated 
                            //总共7次malloc,但是只释放了1次,1120字节被申请 
==3101== 
==3101== LEAK SUMMARY:  //泄漏总结
==3101==    definitely lost: 16 bytes in 1 blocks //明确泄漏
==3101==    indirectly lost: 80 bytes in 5 blocks //间接泄漏
==3101==      possibly lost: 0 bytes in 0 blocks //可疑泄漏
==3101==    still reachable: 0 bytes in 0 blocks //可回收但没回收
==3101==         suppressed: 0 bytes in 0 blocks //系统忽略的内存
==3101== Rerun with --leak-check=full to see details of leaked memory
==3101== 
==3101== For counts of detected and suppressed errors, rerun with: -v
==3101== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
                        //崩溃、越界、野指针的情况
相关推荐
小林ixn10 小时前
LeetCode 206. 反转链表(迭代 + 递归详解)
算法·leetcode·链表
退休倒计时12 小时前
【每日一题】LeetCode 142. 环形链表 II TypeScript
算法·leetcode·链表·typescript
花间相见14 小时前
【LeetCode02】—— 两数之和:哈希表入门经典详解
数据结构·散列表
zhengzhouliuhaha15 小时前
智能医疗设备控费系统:以全院一体化管控,筑牢医疗资源“安全阀”
大数据·数据结构·人工智能·算法·安全·机器学习·软件需求
Yiyaoshujuku17 小时前
化合物数据集API接口(数据结构及样例)
java·网络·数据结构
fu的博客17 小时前
【数据结构16】图:基于邻接矩阵、邻接表实现DFS/BFS
数据结构·算法
言存18 小时前
力扣热题283 移动零
数据结构·算法·leetcode
Lewiis18 小时前
白话桶排序
数据结构·算法·golang·排序算法
iiiiyu19 小时前
IO流相关编程题
java·大数据·开发语言·数据结构·数据库·mysql
Darling噜啦啦20 小时前
JS 数据结构实战:从栈队列到链表,一文吃透数组底层原理与线性数据结构
前端·javascript·数据结构