考研笔记整理~🥝🥝
之前的博文链接在此:数据结构02:线性表[顺序表+链表]_线性链表-CSDN博客~🥝🥝
本篇作为链表的代码补充,供小伙伴们参考~🥝🥝
- 第1版:王道书的课后习题~🧩🧩
**编辑:**梅头脑🌸
参考用书: 王道考研《2025年 数据结构考研复习指导》
目录
[🧵01 删除所有值为x的结点](#🧵01 删除所有值为x的结点)
[🧵02 删除链表最小值](#🧵02 删除链表最小值)
[🧵03 链表逆置](#🧵03 链表逆置)
[🧵05 寻找两个链表的公共节点](#🧵05 寻找两个链表的公共节点)
[🧵06 有序表删除重复元素](#🧵06 有序表删除重复元素)
[🧵07 无序表删除重复元素](#🧵07 无序表删除重复元素)
[🧵08 从递增链表A和B中的公共元素产生单链表C](#🧵08 从递增链表A和B中的公共元素产生单链表C)
[🧵09 从递增链表A和B中的公共元素存放于单链表A](#🧵09 从递增链表A和B中的公共元素存放于单链表A)
[🧵10 判断序列B是否是序列A的连续子序列](#🧵10 判断序列B是否是序列A的连续子序列)
[🧵11 判断带头结点的循环双链表是否对称](#🧵11 判断带头结点的循环双链表是否对称)
[🧵12 将循环单链表 h2 链接到 h1 之后](#🧵12 将循环单链表 h2 链接到 h1 之后)
[🧵13 以访问频度降序排列非循环双链表](#🧵13 以访问频度降序排列非循环双链表)
[🧵14 不带头结点的单链表循环右移](#🧵14 不带头结点的单链表循环右移)
[🧵15 判断单链表是否存在环](#🧵15 判断单链表是否存在环)
[🧵16 不带头结点的单链表孪生和](#🧵16 不带头结点的单链表孪生和)
🧵01 删除所有值为x的结点
🧩题目
在带头结点的单链表工中,删除所有值为x的结点,并释放其空间,假设值为x的结,点
不唯一,试编写算法以实现上述操作。
📇解题思路
- 从头到尾遍历链表,如果发现 x 就执行删除操作;
⌨️解题代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList createList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
return head;
}
bool Delete_X(LinkList& L, int x) {
if (L == nullptr || L->next == nullptr) return false;
LNode* pre = L;
LNode* p = L->next;
while (p != nullptr) {
if (p->data == x) {
pre->next = p->next;
delete p;
p = pre->next;
}
else {
pre = p;
p = p->next;
}
}
return true;
}
int main()
{
vector<int> vec = { 0, 4, 3, 2, 1, 0, 0, 0, 0, 2 };
LinkList L = createList(vec);
// int x = 2;
int x = 0;
bool result = Delete_X(L, x);
while (L->next != nullptr) {
cout << L->next->data << " ";
L = L->next;
}
L == nullptr;
return 0;
}
🧵02 删除链表最小值
🧩题目
试编写在带头结点的单链表中删除一个最小值结点的高效算法(假设该结点唯一)。
📇解题思路
- 使用指针 p 遍历链表,使用指针 min 记录最小节点,然后实行删除操作~
⌨️解题代码(含头结点)
cpp
// 删除带头结点的单链表中最小值结点
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList createList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
return head;
}
bool Delete_Min(LinkList& L) {
if (L == nullptr || L->next == nullptr) return false;
int minNode = INT_MAX;
LNode* pre = L; LNode* p = L->next;
LNode* minPre = pre; LNode* minP = p;
while (p != nullptr) {
if (p->data < minNode) {
minNode = p->data;
minPre = pre;
minP = p;
}
pre = p;
p = p->next;
}
minPre->next = minP->next;
delete minP;
return true;
}
int main()
{
vector<int> vec = { 0, 4, 3, 2, 1, -1, 0, 0, 0, 2 };
LinkList L = createList(vec);
bool result = Delete_Min(L);
while (L->next != nullptr) {
cout << L->next->data << " ";
L = L->next;
}
L = nullptr;
return 0;
}
⌨️解题代码(无头结点)
cpp
// 删除无头结点的单链表中最小值结点
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList createList(const vector<int>& vec) {
if (vec.empty() == true) return nullptr;
LNode* head = new LNode(vec[0]);
LNode* tail = head;
for (int i = 1; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
tail->next = temp;
tail = tail->next;
}
return head;
}
bool Delete_Min(LinkList& L) {
if (L == nullptr) return false;
if (L->next == nullptr) {
L = nullptr;
return true;
}
int minNode = INT_MAX;
LNode* pre = L; LNode* p = L->next;
LNode* minPre = pre; LNode* minP = p;
while (p != nullptr) {
if (p->data < minNode) {
minNode = p->data;
minPre = pre;
minP = p;
}
pre = p;
p = p->next;
}
minPre->next = minP->next;
delete minP;
return true;
}
int main()
{
vector<int> vec = { 0, 4, 3, 2, 1, -1, 0, 0, 0, 2 };
// vector<int> vec = { 0 };
LinkList L = createList(vec);
bool result = Delete_Min(L);
while (L != nullptr) {
cout << L->data << " ";
L = L->next;
}
L = nullptr;
return 0;
}
🧵03 链表逆置
🧩题目
试编写算法将带头结点的单链表就地逆置,所谓"就地"是指辅助空间复杂度为 O(1)。
📇算法思路
- 把链表分成2个,使用头插法分别将第2个链表的节点插入第一个链表,实现逆序插入的效果。
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList createList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
return head;
}
bool Reverse(LinkList& L) {
if (L == nullptr || L->next == nullptr) return false;
LNode* p = L->next;
LNode* q = p->next;
LNode* r;
p->next = nullptr;
while (q != nullptr) {
r = q->next;
q->next = p;
p = q;
q = r;
}
L->next = p;
return true;
}
int main()
{
vector<int> vec = { 4, 3, 2, 1 };
/*vector<int> vec = { 4 };*/
LinkList L = createList(vec);
bool result = Reverse(L);
while (L->next != nullptr) {
cout << L->next->data << " ";
L = L->next;
}
L = nullptr;
return 0;
}
🧵05 寻找两个链表的公共节点
🧩题目
给定两个单链表,试分析找出两个链表的公共结点的思想(不用写代码)。
📇解题思路
这是考试题,如果我来得及写下篇博文的话,会有代码。
🧵06 有序表删除重复元素
🧩题目
设C= {a1,b1,a2,b2,...,an,bn}为线性表,采用带头结点的单链表存放,设计一个就地算法,将其拆分为两个线性表,使得A={a1,a2,...,an},B={bn,...,b2, b1}。
📇算法思路
- 遍历链表,以count表示下标,顺次摘下指针p指到的每个元素:
- count % 2 == 0,表示这是A链表的元素,使用尾插法建立建表;
- count % 2 == 1,表示这是B链表的元素,使用头插法建立建表;
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList createList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
return head;
}
bool Split(LinkList& C, LinkList& A, LinkList& B) {
if (C == nullptr || C->next == nullptr) return false;
LNode* p = C->next; LNode* p1 = A; LNode* p2 = B->next;
LNode* q;
int count = 1;
while (p != nullptr) {
q = p->next;
C->next = q;
p->next = nullptr;
if (count % 2 == 1) {
p1->next = p;
p1 = p1->next;
}
else {
B->next = p;
p->next = p2;
p2 = B->next;
}
p = q;
count++;
}
C = nullptr;
return true;
}
int main()
{
vector<int> vec = { 4, 3, 2, 1 };
// vector<int> vec = { 0, 4, 3, 2, 1, 0, 0, 0, 0, 2 };
LinkList L = createList(vec);
LinkList L1 = new LNode(); L1->next = nullptr;
LinkList L2 = new LNode(); L2->next = nullptr;
bool result = Split(L, L1, L2);
cout << "L1: ";
while (L1->next != nullptr) {
cout << L1->next->data << " ";
L1 = L1->next;
}
cout << endl;
cout << "L2: ";
while (L2->next != nullptr) {
cout << L2->next->data << " ";
L2 = L2->next;
}
cout << endl;
L1 == nullptr;
L2 == nullptr;
return 0;
}
🧵07 无序表删除重复元素
🧩题目
在一个递增有序的单链表中,存在重复的元素。设计算法删除重复的元素,例如(7,10,10,21,30,42,42,42,51,70)将变为(7,10,21,30,42,51,70)。
📇算法思路
- 呃,这与第1题和第2题的思路是完全一致的,找到节点p 和 pre,如果 p->data == pre->data,执行删除操作就可以了~
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList createList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
return head;
}
bool Delete_Same(LinkList& L) {
if (L == nullptr || L->next == nullptr) return false;
LNode* pre = L;
LNode* p = L->next;
while (p != nullptr) {
if (p->data == pre->data) {
pre->next = p->next;
delete p;
p = pre->next;
}
else {
pre = p;
p = p->next;
}
}
return true;
}
int main()
{
vector<int> vec = { 7, 10, 10, 21, 30, 42, 42, 42, 51, 70 };
LinkList L = createList(vec);
bool result = Delete_Same(L);
while (L->next != nullptr) {
cout << L->next->data << " ";
L = L->next;
}
L == nullptr;
return 0;
}
🧵08 从递增链表A和B中的公共元素产生单链表C
🧩题目
设A和B是两个单链表(带头结点),其中元素递增有序。设计一个算法从A和B中的
公共元素产生单链表 C,要求不破坏A、B的结点。
📇算法思路
- 遍历链表,使用 p1指针 遍历A,使用 p2指针 遍历B,使用 p指针 遍历C;
- 如果 p1->data == p2->data,将p1->data记入单链表C,p往后移动1位;这里也设置了p1->data != lastmin,防止相同的数据重复判定陷入死循环,同时剔除了链表C的重复元素;
- 如果 p1->data < p2->data,指针p1往后移动1位;
- 如果不是以上情况,指针p2 往后移动1位;
- 如果指针p1、p2 其中之一遍历到末尾,停止循环,把另一个链表的末尾搬到链表C的末尾;
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList createList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
return head;
}
LinkList Create_Same(LinkList& A, LinkList& B) {
if (A == nullptr || A->next == nullptr) return nullptr;
if (B == nullptr || B->next == nullptr) return nullptr;
LinkList C = new LNode(); C->next = nullptr;
LNode* p1 = A->next;
LNode* p2 = B->next;
LNode* p = C;
int min = INT_MAX; int lastmin = INT_MAX;
while (p1 != nullptr && p2 != nullptr) {
min = p1->data < p2->data ? p1->data : p2->data;
if ((p1->data == p2->data) && (p1->data != lastmin)) {
lastmin = min;
LNode* temp = new LNode(min);
p->next = temp;
temp->next = nullptr;
p = p->next;
}
else if (p1->data < p2->data) {
p1 = p1->next;
}
else {
p2 = p2->next;
}
}
return C;
}
int main()
{
vector<int> vec1 = { 7, 10, 10, 21, 30, 42, 42, 42, 51, 70 };
vector<int> vec2 = { 17, 37, 37, 42, 43, 43, 46, 50, 51, 69 };
LinkList A = createList(vec1);
LinkList B = createList(vec2);
LinkList C = Create_Same(A, B);
while (C->next != nullptr) {
cout << C->next->data << " ";
C = C->next;
}
C == nullptr;
return 0;
}
🧵09 从递增链表A和B中的公共元素存放于单链表A
🧩题目
已知两个链表A和B分别表示两个集合,其元素递增排列。编制函数,求A与B的交集,并存放于A链表中。
📇算法思路
- 使用指针p1遍历A,指针p2遍历B;
- 如果p1->data == p2->data,保留A中的元素,两个指针同时后移;
- 如果p1->data ! = p2->data,指向数字较小的指针向前移动;
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList createList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
return head;
}
LinkList Find_Common(LinkList& A, LinkList& B) {
if (A == nullptr || A->next == nullptr) return nullptr;
if (B == nullptr || B->next == nullptr) return nullptr;
LNode* p1 = A->next; LNode* pre1 = A;
LNode* p2 = B->next;
while (p1 != nullptr && p2 != nullptr) {
if ((p1->data < p2->data)) {
LNode* temp = p1;
pre1->next = p1->next;
p1 = p1->next;
delete(temp);
}
else if (p1->data == p2->data) {
pre1 = p1;
p1 = p1->next;
p2 = p2->next;
}
else {
p2 = p2->next;
}
}
// p1若未遍历到末尾,未遍历到的元素全部舍去
if (p1 != nullptr)
pre1->next = nullptr;
return A;
}
int main()
{
vector<int> vec1 = { 7, 10, 11, 21, 30 };
vector<int> vec2 = { 10, 30, 38, 42, 43 };
//vector<int> vec1 = { 7, 10, 11, 21, 30, 37, 42, 43, 51, 70 };
//vector<int> vec2 = { 10, 37, 38, 42, 43, 45, 46, 50, 51, 69 };
LinkList A = createList(vec1);
LinkList B = createList(vec2);
Find_Common(A, B);
while (A->next != nullptr) {
cout << A->next->data << " ";
A = A->next;
}
A = nullptr;
return 0;
}
🧵10 判断序列B是否是序列A的连续子序列
🧩题目
两个整数序列A=a1,a2,a3,...,an和B=b1,b2,b3,...,bn已经存入两个单链表中,设计一个算法,判断序列B是否是序列A的连续子序列。
📇算法思路
- 使用指针p1遍历A,指针p2遍历B;
- 如果p1->data ! = p2->data,p1向后移动,直到如果p1->data == p2->data;
- 如果p1->data == p2->data,p1、p2同时向后与比较,直到p1->data ! = p2->data或遍历到任一链表的末尾;
- 此时如果p2没有遍历完,那么p2就不是p1的连续子序列。
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList CreateList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
return head;
}
bool Is_Sub(LinkList& A, LinkList& B) {
if (A == nullptr || A->next == nullptr) return false;
if (B == nullptr || B->next == nullptr) return true;
LNode* p1 = A->next; LNode* pre1 = A;
LNode* p2 = B->next;
while (p1 != nullptr && p2 != nullptr && p1->data != p2->data) {
p1 = p1->next;
}
while (p1 != nullptr && p2 != nullptr) {
if (p1->data == p2->data) {
p1 = p1->next;
p2 = p2->next;
}
else {
return false;
}
}
// p2若未遍历到末尾,也不是A的子序列
if (p2 != nullptr) return false;
return A;
}
int main()
{
vector<int> vec1 = { 7, 10, 11, 21, 30 };
//vector<int> vec2 = { 10, 11, 21 };
vector<int> vec2 = { 11, 21, 30, 40 };
LinkList A = CreateList(vec1);
LinkList B = CreateList(vec2);
bool result = Is_Sub(A, B);
if (result == 0) {
cout << "结果为:false" << endl;
}
else {
cout << "结果为:true" << endl;
}
A = nullptr;
return 0;
}
🧵11 判断带头结点的循环双链表是否对称
🧩题目
设计一个算法用于判断带头结点的循环双链表是否对称。
📇算法思路
- 使用指针pre从前向后遍历,指针pre从后向前遍历;
- 如果在指针相遇以前,phead->data != ptail->data,那就不是对称链表;
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct DNode {
int data;
struct DNode* next;
struct DNode* prior;
DNode() : data(0), next(nullptr), prior(nullptr) {}
DNode(int x) : data(x), next(nullptr), prior(nullptr) {}
}DNode, * DLinkList;
DLinkList Create_DList(const vector<int>& vec) {
DNode* head = new DNode();
DNode* p = head;
for (int i = 0; i < vec.size(); i++) {
DNode* temp = new DNode(vec[i]);
p->next = temp;
temp->prior = p;
p = p->next;
}
p->next = head;
head->prior = p;
return head;
}
bool Is_Sym(DLinkList& DL) {
if (DL == nullptr) return false;
DNode* phead = DL->next;
DNode* ptail = DL->prior;
while (phead != ptail) {
if (phead->data != ptail->data) return false;
phead = phead->next;
ptail = ptail->prior;
}
return true;
}
int main()
{
// vector<int> vec = { 7, 10, 11, 10, 7 };
// vector<int> vec = { 7, 10, 11, 11, 10, 7 };
vector<int> vec = { 7, 10, 11, 12, 10, 7 };
DLinkList DL = Create_DList(vec);
int result = Is_Sym(DL);
if (result == true) {
cout << "是循环队列" << endl;
}
else {
cout << "不是循环队列" << endl;
}
return 0;
}
🧵12 将循环单链表 h2 链接到 h1 之后
🧩题目
有两个循环单链表,链表头指针分别为 h1和h2,编写一个函数将链表 h2 链接到链表h1之后,要求链接后的链表仍保持循环链表形式。
📇算法思路
- 使用指针h1、t1分别作为L1的头结点、尾结点,使用指针h2、t2分别作为L2的头结点、尾结点;
- L2的头结点的下一个节点链入L1的尾结点,L2的尾结点链入L1的头结点,返回h1;
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList CreateList(const vector<int>& vec) {
LNode* head = new LNode();
LNode* p = head;
for (int i = 0; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
p->next = temp;
p = p->next;
}
p->next = head;
return head;
}
LNode* Combine(LinkList& L1, LinkList& L2) {
if (L1 == nullptr || L2 == nullptr) return nullptr;
LNode* h1 = L1;
LNode* h2 = L2;
LNode* t1 = L1->next;
LNode* t2 = L2->next;
while (t1->next != h1) {
t1 = t1->next;
}
while (t2->next != h2) {
t2 = t2->next;
}
t1->next = h2->next;
t2->next = h1;
return h1;
}
int main()
{
vector<int> vec1 = { 0, 1, 2, 3, 4 };
vector<int> vec2 = { 5, 6, 7, 8, 9 };
LinkList L1 = CreateList(vec1);
LinkList L2 = CreateList(vec2);
LNode* head = Combine(L1, L2);
LNode* p = head;
while (p->next != head) {
cout << p->next->data << " ";
p = p->next;
}
head == nullptr;
return 0;
}
🧵13 以访问频度降序排列非循环双链表
🧩题目
设有一个带头结点的非循环双链表工,其每个结点中除有 pre、data 和 next 城外,还有一个访问频度域 freq,其值均初始化为零。每当在链表中进行一次 Locate(L,x)运算时,令值为x的结点中 freq域的值增1,并使此链表中的结点保持按访问频度递减的顺序排列,且最近访问的结点排在频度相同的结点之前,以便使频繁访问的结点总是靠近表头。试编写符合上述要求的Locate(L,x)函数,返回找到结点的地址,类型为指针型。
📇算法思路1:交换数据
- 使用指针p遍历链表,执行查找的功能,首先找到目标节点;
- 如果找到目标节点,其频度++,否则返回错误;
- 使用指针q遍历链表,找到第1个 q的频度<= p的频度 的节点;
- 交换p和q节点内的数据。
备注:怎么说呢,这个行为就好像搬家的时候把人和家具搬走了,但是没有搬走房子....
⌨️算法代码1
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct DNode {
int data;
int freq;
struct DNode* next;
struct DNode* prior;
DNode() : data(0), freq(0), next(nullptr), prior(nullptr) {}
DNode(int x) : data(x), freq(0), next(nullptr), prior(nullptr) {}
}DNode, * DLinkList;
DLinkList Create_DList(const vector<int>& vec) {
DNode* head = new DNode();
DNode* p = head;
for (int i = 0; i < vec.size(); i++) {
DNode* temp = new DNode(vec[i]);
p->next = temp;
temp->prior = p;
p = p->next;
}
return head;
}
// 鸡贼地交换两个节点的数据,而非真正交换节点
void swap(DNode* a, DNode* b) {
int temp = a->data;
a->data = b->data;
b->data = temp;
int temp2 = a->freq;
a->freq = b->freq;
b->freq = temp2;
}
DNode* Locate(DLinkList& DL, int target) {
if (DL == nullptr) return nullptr;
DNode* p = DL->next;
while (p != nullptr && p->data != target) {
p = p->next;
}
if (p != nullptr) {
p->freq++;
}
else {
cout << "Not found" << endl;
return nullptr;
}
DNode* q = DL->next;
while (q != nullptr && q->freq > p->freq) {
q = q->next;
}
swap(p, q);
return q;
}
int main()
{
vector<int> vec = { 9, 10, 11, 12, 13 };
DLinkList DL = Create_DList(vec);
DNode* index = nullptr;
index = Locate(DL, 12);
if (index != nullptr) cout << "data: " << DL->next->data << " freq: " << DL->next->freq << endl;
index = Locate(DL, 10);
if (index != nullptr) cout << "data: " << DL->next->data << " freq: " << DL->next->freq << endl;
index = Locate(DL, 8);
if (index != nullptr) cout << "data: " << DL->next->data << " freq: " << DL->next->freq << endl;
index = Locate(DL, 12);
if (index != nullptr) cout << "data: " << DL->next->data << " freq: " << DL->next->freq << endl;
int i = 0;
while (DL->next != nullptr) {
cout << "i: " << i++ << " data: " << DL->next->data << " freq: " << DL->next->freq << endl;
DL = DL->next;
}
return 0;
}
📇算法思路2:交换节点
- 使用指针p遍历链表,执行查找的功能,首先找到目标节点;
- 如果找到目标节点,其频度++,否则返回错误;
- 使用指针q遍历链表,找到第1个 q的频度<= p的频度 的节点;
- 把p摘下来,插入q的前面。
备注:嗯,这个就是搬家的时候把人、家具和房子都搬走了,这就正常多了(?)
⌨️算法代码2
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct DNode {
int data;
int freq;
struct DNode* next;
struct DNode* prior;
DNode() : data(0), freq(0), next(nullptr), prior(nullptr) {}
DNode(int x) : data(x), freq(0), next(nullptr), prior(nullptr) {}
}DNode, * DLinkList;
DLinkList Create_DList(const vector<int>& vec) {
DNode* head = new DNode();
DNode* p = head;
for (int i = 0; i < vec.size(); i++) {
DNode* temp = new DNode(vec[i]);
p->next = temp;
temp->prior = p;
p = p->next;
}
return head;
}
DNode* Locate(DLinkList& DL, int target) {
if (DL == nullptr) return nullptr;
DNode* p = DL->next;
DNode* pre = DL;
while (p != nullptr && p->data != target) {
pre = p;
p = p->next;
}
if (p != nullptr) {
p->freq++;
p->prior->next = p->next;
p->next->prior = p->prior;
}
else {
cout << "Not found" << endl;
return nullptr;
}
DNode* q = DL->next;
while (q != nullptr && q->freq > p->freq) {
q = q->next;
}
q->prior->next = p;
p->prior = q->prior;
p->next = q;
q->prior = p;
return p;
}
int main()
{
vector<int> vec = { 9, 10, 11, 12, 13 };
DLinkList DL = Create_DList(vec);
DNode* index = nullptr;
index = Locate(DL, 12);
if (index != nullptr) cout << "data: " << DL->next->data << " freq: " << DL->next->freq << endl;
index = Locate(DL, 10);
if (index != nullptr) cout << "data: " << DL->next->data << " freq: " << DL->next->freq << endl;
index = Locate(DL, 8);
if (index != nullptr) cout << "data: " << DL->next->data << " freq: " << DL->next->freq << endl;
index = Locate(DL, 12);
if (index != nullptr) cout << "data: " << DL->next->data << " freq: " << DL->next->freq << endl;
int i = 0;
while (DL->next != nullptr) {
cout << "i: " << i++ << " data: " << DL->next->data << " freq: " << DL->next->freq << endl;
DL = DL->next;
}
return 0;
}
🧵14 不带头结点的单链表循环右移
🧩题目
设将n(n>1)个整教存放到不带头结点的单链表L中,设计算法将L中保存的序列循环右移大(0<k<n)个位置,例如,若k=1、则将链表{0,1,2,3}变为{3,0,1,2}。要求,
1)给出算法的基本设计思想。
2)根据设计思想,采用C或 C++语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。
📇算法思路
- **算法思想:**把单链表变成环形链表,然后从链表中间砍一刀;
- **时间复杂度:**O(n);
- **空间复杂度:**O(1)。
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList CreateList(const vector<int>& vec) {
if (vec.empty() == true) return nullptr;
LNode* head = new LNode(vec[0]);
LNode* tail = head;
for (int i = 1; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
tail->next = temp;
tail = tail->next;
}
return head;
}
LNode* Rotate_Right(LinkList& L, int k) {
if (L == nullptr) return nullptr;
if (k <= 0) return L;
LNode* p = L;
LNode* t = L;
int count = 1;
while (t->next != nullptr) {
t = t->next;
count++;
}
t->next = p;
while (count - k > 1) {
p = p->next;
count--;
}
LNode* h1 = p->next;
p->next = nullptr;
return h1;
}
int main()
{
vector<int> vec = { 0, 1, 2, 3 };
LinkList L = CreateList(vec);
LNode* first = Rotate_Right(L, 1);
LNode* p = first;
while (p != nullptr) {
cout << p->data << " ";
p = p->next;
}
p = nullptr;
return 0;
}
🧵15 判断单链表是否存在环
🧩题目
单链表有环,是指单链表的最后一个结点的指针指向了链表中的某个结点(通常单链表的最后一个结点的指针域是空的)。试编写算法判断单链表是否存在环。
1)给出算法的基本设计思想,
2)根据设计思想,采用C或 C+-+语言描述算法,关键之处给出注释,
3)说明你所设计算法的时间复杂度和空间复杂度。
📇算法思路
- **算法思想:**使用快慢指针,如果在fast遍历到nullptr之前有相遇的时候,那就是有环。
- **时间复杂度:**O(n);
- **空间复杂度:**O(1)。
⌨️算法代码
cpp
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
if (!head || !head->next) return NULL;
ListNode* slow = head, * fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
break; // 检测到环
}
}
// 检查是否真的有环
if (fast == NULL || fast->next == NULL) {
return NULL; // 没有环
}
// 寻找环的起始点
slow = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return slow; // 返回环的起始点
}
};
备注:懒得想测试用例了, 测试可以跑leetcode~
面试题 02.08. 环路检测 - 力扣(LeetCode)
🧵16 不带头结点的单链表孪生和
🧩题目
设有一个长度n(n为偶数)的不带头结点的单链表,且结点值都大于0,设计算法求这个单链表的最大孪生和。孪生和定义为一个结点值与其生结点值之和,对于第i个结点(从0开始),其孪生结点为第n-i-1个结点。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或 C++语言描述算法,关键之处给出注释,
3)说明你的算法的时间复杂度和空间复杂度。
📇算法思路
- 算法思想:
- 使用快慢指针,锁定链表中间和末尾的元素;
- 后半部分的链表使用头插法逆置;
- 第1个指针从头部开始,第2个指针从中部开始,向后遍历,计算求和的最小值;
- **时间复杂度:**O(n);
- **空间复杂度:**O(1)。
⌨️算法代码
cpp
#include <iostream>
#include <vector>
using namespace std;
typedef struct LNode {
int data;
struct LNode* next;
LNode() : data(0), next(nullptr) {}
LNode(int x) : data(x), next(nullptr) {}
}LNode, * LinkList;
LinkList CreateList(const vector<int>& vec) {
if (vec.empty() == true) return nullptr;
LNode* head = new LNode(vec[0]);
LNode* tail = head;
for (int i = 1; i < vec.size(); i++) {
LNode* temp = new LNode(vec[i]);
tail->next = temp;
tail = tail->next;
}
return head;
}
int MaxSum(LinkList& L) {
if (L == nullptr) return false;
LNode* slow = L;
LNode* fast = L->next;
while (fast->next != nullptr) {
slow = slow->next;
fast = fast->next;
if (fast->next != nullptr) {
fast = fast->next;
}
}
LNode* p = slow->next;
LNode* q = p->next;
slow->next = nullptr;
while (p != nullptr) {
p->next = nullptr;
p->next = slow->next;
slow->next = p;
p = q;
if (q != nullptr) q = q->next;
}
int sum = INT_MIN;
LNode* head = L;
LNode* tail = fast;
while (head != nullptr && tail != nullptr) {
sum = max(sum, head->data + tail->data);
head = head->next;
tail = tail->next;
}
return sum;
}
int main()
{
//vector<int> vec = { 0, 1, 2, 3, 4, 5 };
vector<int> vec = { 7, 10, 11, 21, 30, 37, 42, 43, 51, 30 };
LinkList L = CreateList(vec);
int result = MaxSum(L);
cout << result << endl;
return 0;
}
🔚结语
博文到此结束,写得模糊或者有误之处,欢迎小伙伴留言讨论与批评,督促博主优化内容{例如有错误、难理解、不简洁、缺功能}等,博主会顶锅前来修改~😶🌫️
我是梅头脑,本片博文若有帮助,欢迎小伙伴动动可爱的小手默默给个赞支持一下,收到点赞的话,博主肝文的动力++~🌟🌟
同系列的博文: 🌸数据结构_梅头脑_的博客-CSDN博客
同博主的博文: 🌸随笔03 笔记整理-CSDN博客