2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】

本文涉及的产品
视觉智能开放平台,视频资源包5000点
视觉智能开放平台,图像资源包5000点
视觉智能开放平台,分割抠图1万点
简介: 数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!

欢迎各位彦祖与热巴畅游本人专栏与博客

你的三连是我最大的动力

以下图片仅代表专栏特色 [点击箭头指向的专栏名即可闪现]

专栏跑道一

➡️网络空间安全——全栈前沿技术持续深入学习

image.gif

专栏跑道二

➡️ 24 Network Security -LJS

image.gif

image.gif

image.gif

专栏跑道三


➡️ MYSQL REDIS Advance operation

image.gif

专栏跑道四

➡️HCIP;H3C-SE;CCIP——LJS[华为、华三、思科高级网络]

image.gif

专栏跑道五

➡️RHCE-LJS[Linux高端骚操作实战篇]

image.png

专栏跑道六

➡️数据结构与算法[考研+实际工作应用+C程序设计]

image.gif

专栏跑道七

➡️RHCSA-LJS[Linux初级及进阶骚技能]

image.gif

image.gif

上节回顾






(1)题目:设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点。

解题思路:

>利用递归,不断将节点的下个节点传入函数
>每个函数执行对应删除操作
image.gif

实现代码:

#include <iostream>
using namespace std;
// 定义链表节点结构体
typedef struct LNode
{
    int data;           // 节点数据
    struct LNode *next; // 指向下一个节点的指针
} LNode, *LinkList; // LinkList 是 LNode 指针类型的别名
// 头插法构建链表
void HeadInsert(LinkList &L)
{
    int val = 0;
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        s->next = L->next;   // 新节点的next指向当前头节点的下一个节点
        L->next = s;         // 头指针的next指向新节点
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 尾插法构建链表
void TailInsert(LinkList &L)
{
    int val = 0;
    LNode *r = L; // r为指向链表最后一个节点的指针
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        r->next = s;         // 尾节点的next指向新节点
        r = s;               // r更新为新节点
        r->next = NULL;      // 新节点的next设为nullptr
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 遍历输出链表元素
void Print(LinkList L)
{
    LNode *p = L->next; // 从头节点的下一个节点开始遍历
    while (p) // 当p不为空时
    {
        cout << p->data << '\t'; // 输出节点数据
        p = p->next;             // 移动到下一个节点
    }
    cout << endl; // 输出换行
}
// 删除链表中所有值为x的节点
void DelValue(LinkList &L, int x)
{
    if (L == NULL) // 如果链表为空,直接返回
    {
        return;
    }
    LNode *p;
    // 如果当前节点的值等于x
    if (L->data == x)
    {
        p = L;            // 将当前节点赋值给p
        L = L->next;     // 将链表的头指针指向下一个节点
        delete p;        // 删除当前节点
        DelValue(L, x);  // 递归调用,继续删除后面的节点
    }
    else
    {
        DelValue(L->next, x); // 否则,递归到下一个节点
    }
}
int main()
{
    LinkList L = new LNode; // 创建链表头节点
    L->next = NULL; // 初始化头节点的next指针为NULL
    TailInsert(L); // 调用尾插法插入数据
    DelValue(L, 2); // 删除值为2的节点
    Print(L);       // 打印链表
}
image.gif

image.gif 编辑

(2)题目:在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法以实现上述操作。

解题思路:

>定义工作指针p、前驱指针pre
>遍历链表,删除元素
image.gif

实现代码:

#include <iostream>
using namespace std;
// 定义链表节点结构体
typedef struct LNode
{
    int data;           // 节点数据
    struct LNode *next; // 指向下一个节点的指针
} LNode, *LinkList; // LinkList 是 LNode 指针类型的别名
// 头插法构建链表
void HeadInsert(LinkList &L)
{
    int val = 0; // 用于存储输入值
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        s->next = L->next;   // 新节点的next指向当前头节点的下一个节点
        L->next = s;         // 头指针的next指向新节点
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 尾插法构建链表
void TailInsert(LinkList &L)
{
    int val = 0; // 用于存储输入值
    LNode *r = L; // r指向链表的尾节点
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        r->next = s;         // 尾节点的next指向新节点
        r = s;               // r更新为新节点
        r->next = NULL;      // 新节点的next设为NULL
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 遍历输出链表元素
void Print(LinkList L)
{
    LNode *p = L->next; // 从头节点的下一个节点开始遍历
    while (p) // 当p不为空时
    {
        cout << p->data << '\t'; // 输出节点数据
        p = p->next;             // 移动到下一个节点
    }
    cout << endl; // 输出换行
}
// 删除链表中所有值为x的节点
void DelValue(LinkList &L, int x)
{
    LNode *p, *pre; // p指向当前节点,pre指向前一个节点
    p = L->next; // 从头节点的下一个节点开始
    pre = L;     // pre初始化为头节点
    while (p) // 当p不为空时
    {
        if (p->data == x) // 如果当前节点的值等于x
        {
            LNode *q = p; // 将当前节点赋值给q
            pre->next = p->next; // 前一个节点的next指向当前节点的下一个节点
            p = p->next; // p移动到下一个节点
            delete q;    // 删除当前节点
        }
        else // 当前节点的值不等于x
        {
            pre = p;     // 更新前一个节点为当前节点
            p = p->next; // p移动到下一个节点
        }
    }
}
int main()
{
    LinkList L = new LNode; // 创建链表头节点
    L->next = NULL; // 初始化头节点的next指针为NULL
    TailInsert(L);  // 调用尾插法插入数据
    DelValue(L, 2); // 删除值为2的节点
    Print(L);       // 打印链表
}
image.gif

(3)题目:设L 为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值。

解题思路:

>利用递归栈进行实现
>栈的特性是后进先出
>所以可以采用递归实现
image.gif

实现代码:

#include <iostream>
using namespace std;
// 定义链表节点结构体
typedef struct LNode
{
    int data;           // 节点数据
    struct LNode *next; // 指向下一个节点的指针
} LNode, *LinkList; // LinkList 是 LNode 指针类型的别名
// 头插法构建链表
void HeadInsert(LinkList &L)
{
    int val = 0; // 用于存储输入值
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        s->next = L->next;   // 新节点的next指向当前头节点的下一个节点
        L->next = s;         // 头指针的next指向新节点
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 尾插法构建链表
void TailInsert(LinkList &L)
{
    int val = 0; // 用于存储输入值
    LNode *r = L; // r指向链表的尾节点
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        r->next = s;         // 尾节点的next指向新节点
        r = s;               // r更新为新节点
        r->next = NULL;      // 新节点的next设为NULL
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 遍历输出链表元素
void Print(LinkList L)
{
    LNode *p = L->next; // 从头节点的下一个节点开始遍历
    while (p) // 当p不为空时
    {
        cout << p->data << '\t'; // 输出节点数据
        p = p->next;             // 移动到下一个节点
    }
    cout << endl; // 输出换行
}
// 递归逆序打印链表
void ReversePrint(LinkList &L)
{
    if (L == NULL) // 如果链表为空,直接返回
    {
        return;
    }
    ReversePrint(L->next); // 递归调用,先打印后面的节点
    cout << L->data << '\t'; // 打印当前节点的数据
}
int main()
{
    LinkList L = new LNode; // 创建链表头节点
    L->next = NULL;         // 初始化头节点的next指针为NULL
    TailInsert(L);          // 调用尾插法插入数据
    // 逆序打印链表的元素
    ReversePrint(L->next); 
}
image.gif

(4)题目:试编写在带头结点的单链表L 中删除一个最小值结点的高效算法(假设最小值结点是唯一的)。

解题思路:

>定义工作指针p、pre
>定义用于保存最小值的指针minP、minPre
>遍历链表找到最小值,用指针标记
>最后修改指针将其删除释放空间
image.gif

实现代码:

#include <iostream>
using namespace std;
// 定义链表节点结构体
typedef struct LNode
{
    int data;           // 节点数据
    struct LNode *next; // 指向下一个节点的指针
} LNode, *LinkList; // LinkList 是 LNode 指针类型的别名
// 头插法构建链表
void HeadInsert(LinkList &L)
{
    int val = 0; // 用于存储输入值
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        s->next = L->next;   // 新节点的next指向当前头节点的下一个节点
        L->next = s;         // 头指针的next指向新节点
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 尾插法构建链表
void TailInsert(LinkList &L)
{
    int val = 0; // 用于存储输入值
    LNode *r = L; // r指向链表的尾节点
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        r->next = s;         // 尾节点的next指向新节点
        r = s;               // r更新为新节点
        r->next = NULL;      // 新节点的next设为NULL
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 遍历输出链表元素
void Print(LinkList L)
{
    LNode *p = L->next; // 从头节点的下一个节点开始遍历
    while (p) // 当p不为空时
    {
        cout << p->data << '\t'; // 输出节点数据
        p = p->next;             // 移动到下一个节点
    }
    cout << endl; // 输出换行
}
// 删除链表中的最小值节点
void DelMinValue(LinkList &L)
{
    // 工作节点
    LNode *p, *pre; // p是当前节点,pre是前驱节点
    p = L->next;     // 从链表的第一个节点开始
    pre = L;        // 前驱节点初始化为头节点
    // 用于保存最值的节点
    LNode *minP, *minPre; // minP是当前最小值节点,minPre是其前驱节点
    minP = p; // 初始化为第一个节点
    minPre = pre; // 初始化为头节点
    // 遍历链表查找最小值节点
    while (p)
    {
        if (p->data < minP->data) // 找到更小的值
        {
            minPre = pre; // 更新前驱节点
            minP = p;     // 更新最小值节点
        }
        pre = p; // 前驱节点向后移动
        p = p->next; // 当前节点向后移动
    }
    // 删除最小值节点
    minPre->next = minP->next; // 将前驱节点的next指向最小值节点的下一个节点
    delete minP; // 释放内存
}
int main()
{
    LinkList L = new LNode; // 创建链表头节点
    L->next = NULL;         // 初始化头节点的next指针为NULL
    TailInsert(L);          // 调用尾插法插入数据
    DelMinValue(L);         // 删除链表中的最小值节点
    Print(L);               // 打印修改后的链表
}
image.gif

(5)题目:试编写算法将带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为 O(1)。

解题思路:

>头插法
image.gif

实现代码:

#include <iostream>
using namespace std;
// 定义链表节点结构体
typedef struct LNode
{
    int data;           // 节点数据
    struct LNode *next; // 指向下一个节点的指针
} LNode, *LinkList; // LinkList 是 LNode 指针类型的别名
// 头插法构建链表
void HeadInsert(LinkList &L)
{
    int val = 0; // 用于存储输入值
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        s->next = L->next;   // 新节点的next指向当前头节点的下一个节点
        L->next = s;         // 头指针的next指向新节点
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 尾插法构建链表
void TailInsert(LinkList &L)
{
    int val = 0; // 用于存储输入值
    LNode *r = L; // r指向链表的尾节点
    while (cin >> val) // 从标准输入读取数据
    {
        LNode *s = new LNode; // 创建新节点
        s->data = val;        // 设置节点数据
        r->next = s;         // 尾节点的next指向新节点
        r = s;               // r更新为新节点
        r->next = NULL;      // 新节点的next设为NULL
        // 如果读取到换行符,结束输入
        if (cin.get() == '\n')
        {
            break;
        }
    }
}
// 遍历输出链表元素
void Print(LinkList L)
{
    LNode *p = L->next; // 从头节点的下一个节点开始遍历
    while (p) // 当p不为空时
    {
        cout << p->data << '\t'; // 输出节点数据
        p = p->next;             // 移动到下一个节点
    }
    cout << endl; // 输出换行
}
// 反转链表
void fn(LinkList &L)
{
    LNode *p, *r; // p用于遍历链表,r用于保存当前节点的下一个节点
    p = L->next;  // 从头节点的下一个节点开始
    L->next = NULL; // 初始化头节点的next为NULL,准备反转
    // 反转链表
    while (p)
    {
        r = p->next; // 保存当前节点的下一个节点
        p->next = L->next; // 将当前节点的next指向当前头节点的next
        L->next = p; // 更新头节点的next为当前节点
        p = r; // 移动到下一个节点
    }
}
int main()
{
    LinkList L = new LNode; // 创建链表头节点
    TailInsert(L);          // 调用尾插法插入数据
    fn(L); // 反转链表
    Print(L); // 打印反转后的链表
}
image.gif























相关文章
|
17天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
数据结构与算法系列学习之串的定义和基本操作、串的储存结构、基本操作的实现、朴素模式匹配算法、KMP算法等代码举例及图解说明;【含常见的报错问题及其对应的解决方法】你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
|
15天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
43 4
|
17天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
15天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
35 0
|
1月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
69 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
1月前
|
机器学习/深度学习 存储 缓存
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
文章主要介绍了排序算法的分类、时间复杂度的概念和计算方法,以及常见的时间复杂度级别,并简单提及了空间复杂度。
24 1
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
|
1月前
|
搜索推荐 算法
数据结构与算法学习十四:常用排序算法总结和对比
关于常用排序算法的总结和对比,包括稳定性、内排序、外排序、时间复杂度和空间复杂度等术语的解释。
19 0
数据结构与算法学习十四:常用排序算法总结和对比
|
1月前
|
存储 缓存 分布式计算
数据结构与算法学习一:学习前的准备,数据结构的分类,数据结构与算法的关系,实际编程中遇到的问题,几个经典算法问题
这篇文章是关于数据结构与算法的学习指南,涵盖了数据结构的分类、数据结构与算法的关系、实际编程中遇到的问题以及几个经典的算法面试题。
29 0
数据结构与算法学习一:学习前的准备,数据结构的分类,数据结构与算法的关系,实际编程中遇到的问题,几个经典算法问题
|
1月前
|
机器学习/深度学习 存储 算法
【数据结构与算法基础】——算法复杂度
【数据结构与算法基础】——算法复杂度
|
5月前
|
算法 C++ Python
数据结构与算法===贪心算法
数据结构与算法===贪心算法

热门文章

最新文章