数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、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;
目录
相关文章
|
8天前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
11天前
|
存储 算法 数据安全/隐私保护
【Python学习篇】Python实验小练习——高级数据结构(五)
【Python学习篇】Python实验小练习——高级数据结构(五)
25 1
|
1天前
|
算法 Java
[Java·算法·中等] LeetCode21. 合并两个有序链表
[Java·算法·中等] LeetCode21. 合并两个有序链表
9 2
|
1天前
|
存储 算法 Go
算法学习:数组 vs 链表
算法学习:数组 vs 链表
6 0
|
5天前
|
算法
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
|
1月前
【移除链表元素】LeetCode第203题讲解
【移除链表元素】LeetCode第203题讲解
|
8天前
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
8天前
|
存储 SQL 算法
LeetCode 83题:删除排序链表中的重复元素【面试】
LeetCode 83题:删除排序链表中的重复元素【面试】
|
8天前
|
存储 SQL 算法
LeetCode 题目 82:删除排序链表中的重复元素 II
LeetCode 题目 82:删除排序链表中的重复元素 II
|
8天前
|
算法 数据挖掘 Python
LeetCode题目25 hard:K个一组翻转链表 【分治策略 Python】
LeetCode题目25 hard:K个一组翻转链表 【分治策略 Python】