排序算法详解:归并排序及其在链表排序中的应用
创作时间:
2025-01-22 07:11:48
作者:
@小白创作中心
排序算法详解:归并排序及其在链表排序中的应用
归并排序是一种高效的排序算法,它采用分治策略将数组分解成更小的子数组,然后将这些子数组合并成一个有序数组。本文将详细介绍归并排序的基本思想、步骤、代码实现、时间复杂度和空间复杂度分析,以及如何使用归并排序对链表进行排序。
思想:
归并排序的基本思想是将两个或多个有序的数组合并成一个有序数组。单个元素可以看作是一个有序数组。
步骤:
- 将数组分解,直到每个子数组只包含一个元素(因为单个元素的数组默认是有序的)。
- 将两两有序的子数组进行合并,重复此步骤,直到整个数组排序完成。
实现代码
#include <iostream> // 包含输入输出流头文件
#include <vector> // 包含vector头文件
using namespace std; // 使用标准命名空间
// 定义Merge函数,用于将两个有序部分合并
void Merge(vector<int>& vec, int l, int mid, int r) {
vector<int> temp; // 创建临时向量用于存储合并后的结果
int i = l; // 初始化左边部分的起始索引
int j = mid + 1; // 初始化右边部分的起始索引
// 将左右两部分按照大小顺序合并到temp中
while (i <= mid && j <= r) {
if (vec[i] <= vec[j]) {
temp.push_back(vec[i]);
i++;
} else {
temp.push_back(vec[j]);
j++;
}
}
// 将左边剩余的元素拷贝到temp中
while (i <= mid) {
temp.push_back(vec[i]);
i++;
}
// 将右边剩余的元素拷贝到temp中
while (j <= r) {
temp.push_back(vec[j]);
j++;
}
// 将合并后的结果拷贝回原始数组vec中的[l, r]区间
i = l;
for (auto x : temp) {
vec[i++] = x;
}
}
// 定义Mergesort函数,用于归并排序
void Mergesort(vector<int>& vec, int l, int r) {
// 若当前区间只有一个元素,则返回
if (l >= r) return;
// 计算中间位置
int mid = (l + r) / 2;
// 分别对左右两部分进行归并排序
Mergesort(vec, l, mid);
Mergesort(vec, mid + 1, r);
// 合并左右两部分
Merge(vec, l, mid, r);
}
int main() {
// 初始化待排序数组
vector<int> vec{ 5,7,3,9,4,8,2,9,1 };
int n = vec.size(); // 获取数组大小
// 对数组进行归并排序
Mergesort(vec, 0, n - 1);
// 输出排序后的结果
for (auto x : vec) {
cout << x << " ";
}
return 0;
}
时间复杂度分析:
归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。
空间复杂度:
O(N),归并排序需要一个与原数组相同长度的数组做辅助来排序。
扩展:(使用归并排序的思想进行链表排序)
首先将待排序的数组转换为单链表,然后使用归并排序对链表进行排序,最后输出排序后的结果。
代码实现:
#include <iostream>
#include <vector>
using namespace std;
// 定义单链表节点结构
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
// 将链表切割成前i个节点和后面的部分,并返回后面部分的头指针
ListNode* cut(ListNode* node, int i) {
ListNode* p = node;
// 找到第i个节点
while (--i && p) {
p = p->next;
}
// 若未找到或p为空,返回nullptr
if (p == nullptr) return nullptr;
ListNode* nxt = p->next;
// 切断前i个节点和后面的部分
p->next = nullptr;
return nxt;
}
// 合并两个有序链表,并返回合并后的链表头指针
ListNode* merge(ListNode* l, ListNode* r) {
ListNode* dummyhead = new ListNode; // 创建虚拟头节点
ListNode* p = dummyhead; // 指针p指向虚拟头节点
// 遍历两个链表,按照升序依次将节点连接到p的后面
while (l && r) {
if (l->val <= r->val) {
p->next = l;
l = l->next;
p = p->next;
} else {
p->next = r;
r = r->next;
p = p->next;
}
}
// 将剩余的节点连接到p的后面
if (l) {
p->next = l;
}
if (r) {
p->next = r;
}
return dummyhead->next; // 返回合并后的链表头指针
}
// 对链表进行归并排序
ListNode* ListMergeSort(ListNode* head) {
int length = 0; // 记录链表长度
ListNode* p = head; // 指针p指向链表头节点
// 计算链表长度
while (p) {
p = p->next;
length++;
}
// 创建虚拟头节点,并指向原始链表头节点
ListNode* dummyhead = new ListNode;
dummyhead->next = head;
// 外层循环,每次将链表分成长度为i的段,i从1开始,每次翻倍,直到超过链表长度
for (int i = 1; i < length; i *= 2) {
ListNode* cur = dummyhead->next; // 指针cur指向当前待合并的段的头节点
ListNode* tail = dummyhead; // 指针tail指向合并后的段的尾节点
while (cur) {
ListNode* left = cur; // 左半部分的头节点
ListNode* right = cut(left, i); // 右半部分的头节点
cur = cut(right, i); // 更新cur指向下一个待合并的段的头节点
tail->next = merge(left, right); // 将左右两部分合并后连接到已排序部分的尾部
while (tail->next) {
tail = tail->next; // 移动tail到已排序部分的尾部
}
}
}
return dummyhead->next; // 返回排序后的链表头指针
}
int main() {
// 初始化待排序数组
vector<int> vec{ 5,7,3,9,4,8,2,9,1 };
// 创建虚拟头节点
ListNode* dummyhead = new ListNode;
ListNode* cur = dummyhead;
// 将待排序数组转换为链表
for (auto x : vec) {
ListNode* newnode = new ListNode;
newnode->val = x;
cur->next = newnode;
cur = cur->next;
}
// 对链表进行归并排序
cur = ListMergeSort(dummyhead->next);
// 输出排序后的结果
while (cur) {
cout << cur->val << " ";
cur = cur->next;
}
return 0;
}
热门推荐
生何首乌与制何首乌
物联网背景下现代物流与供应链管理创新与发展
英聽怎麼練 ?英文精聽8步驟,培養扎實的英文聽力訓練
约1/4人群可能发生心衰,八大危险因素不容忽视!
GGII:预计构网型储能未来5年在全球有望达到20%的渗透率
十二星座的项链是什么样子的 十二星座专属项链
丁卡因和利多卡因区别是什么
长期吃降压药危害
佛手有什么药用功能
减速器与电机连接方式详解:四种主流方案及应用场景
糖尿病病人能吃芒果吗
高压变频柜KMBY-12旁路方案详解
八字日柱排盘免费查询 日柱合婚注意事项
笔记本电脑常见故障及解决方法:从硬件到软件的全面指南
南昌年轻人爱上户外徒步 医生提醒:徒步好处多但需量力而行
家庭资产配置黄金比例:记住这个"4321"法则就够了
摄影必修课:ISO参数详解与应用技巧
养父母与养子女能不能解除收养关系
肥胖与健康的关系
小腿抽筋怎么治疗最快最有效
会计助理的工作职责包括哪些方面?
旅行社导游岗位的日常职责有哪些?
大学生必看的励志电影精选:在光影中寻找成长的力量
生态系统的能量流与物质循环机制探究
东非最大水电工程彰显中国企业建设实力和社会责任
2024苏州中考分数线公布!各区域学校录取线全解析
铸造生产过程中常见缺陷及解决方法
中老年人饮茶指南:四种养生茶的保健功效
春雪旅行计划|赏长白春雪,探万物苏醒
阿司匹林常见的副作用有哪些?医生:这3种一定要知道