数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、pos位置之前插入结点、pos位置删除结点及其复用、销毁链表函数

简介: 数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、pos位置之前插入结点、pos位置删除结点及其复用、销毁链表函数

线性表之双向链表(上)

头插函数

头插的思路比较简单,创建一个新结点,在哨兵位结点和第一个结点之间链接起来就可以。头插函数在链表为空时不会出问题,所以不需要多加断言。

void ListPushFront(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTNode* newnode = BuyListNode(x);
    LTNode* next = phead->next;
 
    phead->next = newnode;
    newnode->prev = phead;
 
    newnode->next = next;
    next->prev = newnode;
}

头删函数

代码

void ListPopFront(LTNode* phead)
{
    assert(phead);
    //链表为空
    assert(phead->next != phead);
 
    LTNode* next = phead->next;
    LTNode* nextNext = next->next;
 
    phead->next = nextNext;
    nextNext->prev = phead;
    free(next);
}

简单思路

查找函数

查找函数实现起来十分简单,直接遍历就可以了。思路与打印函数是一致的。

LTNode* ListFind(LTNode* phead, LTDataType x)
{
    assert(phead);
 
    LTNode* cur = phead->next;
    while (cur != phead)
    {
        if (cur->data == x)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

pos位置之前插入结点

第一种方法(更好)

我们不使用大部分教材上的方法,即不多创建一个结点,直接进行指针的改变;这样就需要对指针改变的顺序有极大的要求,一旦指针改变的顺序不一样,就不能实现插入。

这里使用的是创建一个结点记录下pos位置的前一个结点,好处是在进行指针改变时不用考虑改变顺序。

代码

//pos位置之前插入结点
void ListInsert(LTNode* pos, LTDataType x)
{
    assert(pos);
    LTNode* posPrev = pos->prev;
    LTNode* newnode = BuyListNode(x);
 
    posPrev->next = newnode;
    newnode->prev = posPrev;
    newnode->next = pos;
    pos->prev = newnode;
 
}

第二种方法

思路

像这样没创建一个posPrev则需要考虑改变的顺序。

同时,实现了pos位置之前插入结点的这个函数之后,就可以复用到头插和尾插当中了。

pos位置删除结点

void ListErase(LTNode* pos)
{
    assert(pos);
 
    LTNode* posPrev = pos->prev;
    LTNode* posNext = pos->next;
 
    posPrev->next = posNext;
    posNext->prev = posPrev;
    free(pos);
}

复用到尾删

void ListPopBack(LTNode* phead)
{
    assert(phead);
    assert(phead->next != phead);
 
    //LTNode* tail = phead->prev;
    //LTNode* tailPrev = tail->prev;
    //free(tail);
 
    //tailPrev->next = phead;
    //phead->prev = tailPrev;
    ListErase(phead->prev);
}

复用到头删

void ListPopFront(LTNode* phead)
{
    assert(phead);
    //链表为空
    assert(phead->next != phead);
 
    //LTNode* next = phead->next;
    //LTNode* nextNext = next->next;
 
    //phead->next = nextNext;
    //nextNext->prev = phead;
    //free(next);
    ListErase(phead->next);
}

双向链表销毁

void ListDestroy(LTNode* phead)
{
    assert(phead);
    LTNode* cur = phead->next;
    while (cur != phead)
    {
        LTNode* next = cur->next;
        free(cur);
        cur = next;
    }
    free(phead);
}

如果传入一级指针则存在野指针的隐患,即销毁完空间之后没有把指针置空

但从设计上考虑,为了保持接口函数的一致性,就统一使用一级指针了。

所以我们就在外面将指针置为空

ListDestroy(phead);
phead = NULL;
目录
相关文章
|
25天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
38 1
|
28天前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
95 4
|
3天前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
41 20
|
26天前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
|
26天前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
25天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
56 1
|
6月前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
6月前
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
6月前
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
66 2
|
7月前
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点.
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点
69 1