数据结构-链表

一.数据结构

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)
                        //崩溃、越界、野指针的情况
相关推荐
小的~~2 小时前
算法题:只出现一次的数字
数据结构·算法
一切皆是因缘际会2 小时前
从概率拟合到内生心智:七层投影架构重构AGI数字生命新范式
大数据·数据结构·人工智能·重构·架构·agi
历程里程碑2 小时前
56 . 高效ET非阻塞IO服务器设计指南
java·运维·服务器·开发语言·数据结构·c++·排序算法
南境十里·墨染春水3 小时前
数据结构 —— 顺序表
数据结构
tongluowan0073 小时前
数据结构 Bitmap(位图)示例 - 用户签到系统
开发语言·数据结构·bitmap·用户签到系统
洛水水3 小时前
Redis对象类型与底层数据结构
数据结构·数据库·redis
Hesionberger3 小时前
LeetCode114:二叉树展开为链表(三解法)
数据结构
一行代码一行诗++3 小时前
循环的嵌套
数据结构·算法
郝学胜-神的一滴3 小时前
干货版《算法导论》05:从集合接口到排序
开发语言·数据结构·c++·程序人生·算法·排序