数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、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;
目录
相关文章
|
3月前
|
机器学习/深度学习 算法 数据挖掘
没发论文的注意啦!重磅更新!GWO-BP-AdaBoost预测!灰狼优化、人工神经网络与AdaBoost集成学习算法预测研究(Matlab代码实现)
没发论文的注意啦!重磅更新!GWO-BP-AdaBoost预测!灰狼优化、人工神经网络与AdaBoost集成学习算法预测研究(Matlab代码实现)
116 0
|
23天前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(一):认识Python、Py解释器作用;编写第一个Python程序;Python中的基本数据结构
认识Python 前提安装好Python,这里使用3.13版本 如今Python作为变成姐最炙手可热的编程语言,它的使用途径涵盖绝大部分生活中需要的开发需要。 许多大型网站就是用Python开发的,例如YouTube、Instagram,还有国内的豆瓣。很多大公司,包括Google、Yahoo等,甚至NASA都大量地使用Python。
305 1
|
2月前
|
机器学习/深度学习 运维 算法
【微电网多目标优化调度】多目标学习者行为优化算法MOLPB求解微电网多目标优化调度研究(Matlab代码实现)
【微电网多目标优化调度】多目标学习者行为优化算法MOLPB求解微电网多目标优化调度研究(Matlab代码实现)
140 1
|
8月前
|
算法 数据可视化 开发者
为什么要学习数据结构与算法
今天,我向大家介绍一门非常重要的课程——《数据结构与算法》。这门课不仅是计算机学科的核心,更是每一位开发者从“小白”迈向“高手”的必经之路。
为什么要学习数据结构与算法
|
10月前
|
负载均衡 算法
架构学习:7种负载均衡算法策略
四层负载均衡包括数据链路层、网络层和应用层负载均衡。数据链路层通过修改MAC地址转发帧;网络层通过改变IP地址实现数据包转发;应用层有多种策略,如轮循、权重轮循、随机、权重随机、一致性哈希、响应速度和最少连接数均衡,确保请求合理分配到服务器,提升性能与稳定性。
2022 11
架构学习:7种负载均衡算法策略
【移除链表元素】LeetCode第203题讲解
【移除链表元素】LeetCode第203题讲解
110 0
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
150 2
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点.
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点
184 1
下一篇
开通oss服务