算法 - 排序 - 二路归并排序 (Two-way Merge Sort)
返回上级:算法 - 查找与排序 (Searching and Sorting)
本文将用C++实现插入二路归并排序算法。
在查看本文之前,需要一些程序语言的基础。
所有排序方法中,统一使用如下库与结构:
// Author: https://blog.youkuaiyun.com/DarkRabbit
// Sorted Dependency
#pragma once
#include <algorithm>
#include <vector>
#include <stack>
template<typename T>
struct MyItem
{
int key;
T data;
MyItem(){ key = -1; }
MyItem(const int& k) : key(k){ }
MyItem(const int& k, const T& d) : key(k), data(d){ }
};
数据表统一使用了std::vector<MyItem<T>>,如果你使用静态数组MyItem<T>[]或指针数组MyItem<T>*,那么还要传入元素数量size。
示例所用数据:
-
元素数量为
size = 15; -
关键字为
key = { 123, 122, 565, 22, 3, 64, 73, 44, 287, 6, 9, 83, 25, 42, 13 }。
文章目录
1 二路归并排序简述 (Introduction)
归并排序,是将两个以上的有序表组合成一个新的有序表。
二路归并基本思想是将数据表的每个元素看成是只有一个元素的有序数据表,然后两两合并,重复过程,直到合并成一个数据表。
其详细过程:
key = { 123, 122, 565, 22, 3, 64, 73, 44, 287, 6, 9, 83, 25, 42, 13 }
两路归并排序,首先将每个元素当成一个有序数据表
0: {123}{122}{565}{ 22}{ 3}{ 64}{ 73}{ 44}{287}{ 6}{ 9}{ 83}{ 25}{ 42}{ 13}
左子表长度:1,两两合并
1: {122, 123}{565, 22}{ 3, 64}{ 73, 44}{287, 6}{ 9, 83}{ 25, 42}{ 13}
2: {122, 123}{ 22, 565}{ 3, 64}{ 73, 44}{287, 6}{ 9, 83}{ 25, 42}{ 13}
3: {122, 123}{ 22, 565}{ 3, 64}{ 73, 44}{287, 6}{ 9, 83}{ 25, 42}{ 13}
4: {122, 123}{ 22, 565}{ 3, 64}{ 44, 73}{287, 6}{ 9, 83}{ 25, 42}{ 13}
5: {122, 123}{ 22, 565}{ 3, 64}{ 44, 73}{ 6, 287}{ 9, 83}{ 25, 42}{ 13}
6: {122, 123}{ 22, 565}{ 3, 64}{ 44, 73}{ 6, 287}{ 9, 83}{ 25, 42}{ 13}
7: {122, 123}{ 22, 565}{ 3, 64}{ 44, 73}{ 6, 287}{ 9, 83}{ 25, 42}{ 13}
左子表子表长度:2,两两合并
8: { 22, 122, 123, 565}{ 3, 64, 44, 73}{ 6, 287, 9, 83}{ 25, 42, 13}
9: { 22, 122, 123, 565}{ 3, 44, 64, 73}{ 6, 287, 9, 83}{ 25, 42, 13}
10: { 22, 122, 123, 565}{ 3, 44, 64, 73}{ 6, 9, 83, 287}{ 25, 42, 13}
11: { 22, 122, 123, 565}{ 3, 44, 64, 73}{ 6, 9, 83, 287}{ 13, 25, 42}
左子表子表长度:4,两两合并
12: { 3, 22, 44, 64, 73, 122, 123, 565}{ 6, 9, 83, 287, 13, 25, 42}
13: { 3, 22, 44, 64, 73, 122, 123, 565}{ 6, 9, 13, 25, 42, 83, 287}
左子表长度:8,两两合并
14: { 3, 6, 9, 13, 22, 25, 42, 44, 64, 73, 83, 122, 123, 287, 565}
2 性能分析 (Performance Analysis)
| 排序方法 | 最好时间 | 最差时间 | 平均时间 | 辅助空间 | 稳定性 |
|---|---|---|---|---|---|
| 归并排序 | O(n log2n) | O(n log2n) | O(n log2n) | O(n) | 稳定 |
3 简单选择排序C++代码 (Selection Sort C++ Code)
// Author: https://blog.youkuaiyun.com/DarkRabbit
// Two-way Merge Sort
// 合并子表
// params:
// list: 整表
// first: 第一个表开始下标
// second: 第二个表开始下标
// firstSize: 第一个子表的长度
template<typename T>
void TwowayMerge(std::vector<MyItem<T>>& list,
int first,
int second,
int firstSize)
{
int size = list.size(); // 表长
int secondSize = firstSize; // 第二个子表长度
if (second + firstSize > size) // 如果第二个子表超出范围
{
secondSize = size - second; // 重新计算长度
}
std::vector<MyItem<T>> tmpList(firstSize + secondSize); // 合并后的临时表
int left = 0;
int right = 0;
while (left < firstSize && right < secondSize) // 依次比较两个子表关键字
{
if (list[first + left].key <= list[second + right].key)
{
tmpList[left + right] = list[first + left]; // 将第一子表元素添加到临时表
left++;
}
else
{
tmpList[left + right] = list[second + right]; // 将第二子表元素添加到临时表
right++;
}
}
while (left < firstSize) // 第一子表还有元素,且全比临时表元素大
{
tmpList[left + right] = list[first + left];
left++;
}
while (right < secondSize) // 第二子表还有元素,且全比临时表元素大
{
tmpList[left + right] = list[second + right];
right++;
}
for (int i = 0; i < tmpList.size(); i++) // 将临时表元素放回原表
{
list[first + i] = tmpList[i];
}
tmpList.clear();
}
template<typename T>
void TwowayMergeSort(std::vector<MyItem<T>>& list)
{
int size = list.size();
int firstSize = 1; // 首次子表长度为1,即每个元素为一个表
while (firstSize < size)
{
// 两两比较子表
for (int i = 0; i < size - firstSize; i += firstSize * 2)
{
TwowayMerge(list, i, i + firstSize, firstSize);
}
firstSize *= 2; // 更新子表长度
}
}
本文介绍了二路归并排序算法,并提供了C++实现。归并排序是一种通过将两个有序子序列合并来创建新有序序列的排序方法。文章包括算法简介、性能分析和C++代码示例。

362

被折叠的 条评论
为什么被折叠?



