排序算法
\qquad本文主要展示归并排序和快速排序。
分析
快速排序和归并排序为什么可以将时间复杂度由其他算法的O(n2)O(n^2)O(n2)降低到O(nlog2n)O(nlog_{2}{n})O(nlog2n)???
- 快速排序的时间复杂度跟每次排序选取的元素在排序后数组的位置有关,越靠近数组中间,排序的速度越快。当每次元素选择最佳(排序区域的中间),只需要log2nlog_{2}nlog2n次便能达到最小分区(start==endstart == endstart==end),每次分区需要nnn次,所以最后时间复杂度为O(n∗log2n)O(n*log_2n)O(n∗log2n)。
- 归并排序的时间复杂度比较稳定,数组经过O(log2n)O(log_2n)O(log2n)次实现数组的最小分割,再经过log2nlog_2nlog2n次数组合并,合并过程中进行数组排序,每层合并需要nnn次运算,所以最后的时间复杂度为O(n∗log2n)O(n*log_2n)O(n∗log2n)。
快速排序
Swap(int* Index1, int* Index2) 交换函数
void Swap(int* Index1, int* Index2) // 交换函数, 实现数组元素的交换
{
int temp = *Index1;
*Index1 = *Index2;
*Index2 = temp;
};
Partition(int* Array, int Start, int End) 排序函数
int Partition(int* Array, int Start, int End)
{
if (Start == End) // 确定返回时机
return Start;
int Middle = (Start + End) / 2; // 确定选取的元素,选取方式自定
Swap(&Array[End], &Array[Middle]); // 将选取的元素和数组片段的最后一个元素交换
int Small = Start - 1; // 小于选取元素位置变量的初始化
for (int Index = Start; Index < End; ++Index)
{
if (Array[Index] < Array[End]) // 如果遍历的当前元素小于选取的元素
{
++Small; // 指向大于选取元素的位置
if (Index != Small) // 如果两个变量不相同,交换对应的数组元素
Swap(&Array[Index], &Array[Small]); // 如果相同,此时还没有出现大于选取元素的元素,不进行交换
}
}// 一次遍历之后,small + 1 指向的元素大于选取的元素
++Small; // 指向该元素
Swap(&Array[End], &Array[Small]); // 交换选取的元素和Small,此时选取元素在数组的位置为排序后的正确位置
return Small; // 返回选取的元素
};
QuickSort(int *Array, int Start, int End, int ArrayLength) 递归调用排序函数
void QuickSort(int *Array, int Start, int End, int ArrayLength)
{
if (Start == End) // 数组片段的头 == 尾
return; // 不在递归
int Middle = Partition(Array, Start, End); // 获得选取的元素下标
for (int i = 0; i < ArrayLength; ++i) // 打印当前数组的排序情况
std::cout << Array[i] << " ";
std::cout << std::endl;
QuickSort(Array, Start, Middle, ArrayLength); // 递归排序 Start 到 Middle
if (Middle + 1 > End) // 防止数组越界
return;
QuickSort(Array, Middle + 1, End, ArrayLength); // 递归排序 Middle + 1 到 End
};
QuickSortFun() 测试函数
void QuickSortFun()
{
int Array[] = { 3,6,8,0,9,7,4,2,1,5 };
int ArrayLength = sizeof(Array) / sizeof(Array[0]);
for (int i = 0; i < ArrayLength; ++i)
std::cout << Array[i] << " ";
std::cout << std::endl;
QuickSort(Array, 0, ArrayLength - 1, ArrayLength);
};
归并排序
void Merge(int* Array, int* Array1, int ArrayLength1, int* Array2, int ArrayLength2)合并函数
void Merge(int* Array, int* Array1, int ArrayLength1, int* Array2, int ArrayLength2) // 合并函数
{
int i = 0, j = 0, k = 0;
while (i < ArrayLength1 && j < ArrayLength2) // 在数组Array上排序 Array1 he1 Array2,两个数组已经有序,因此合并时时间复杂度为O(n)
{
if (Array1[i] < Array2[j])
{
Array[k++] = Array1[i++];
}
else
{
Array[k++] = Array2[j++];
}
}
while(i < ArrayLength1) Array[k++] = Array1[i++]; // 当Array2数组遍历完成,Array1数组未遍历完成
while(j < ArrayLength2) Array[k++] = Array2[j++]; // 当Array1数组遍历完成,Array2数组未遍历完成
};
void MergeSort(int* Array, int ArrayLength)分割函数
void MergeSort(int* Array, int ArrayLength) // 数组分割
{
if (ArrayLength < 2) // 长度为 1 时,结束递归, 和并数组
return;
int Middle = ArrayLength / 2;
int* Array1 = new int[Middle]; // 按照分割点生成 Array1
int* Array2 = new int[ArrayLength - Middle]; // 生成 Array2
int i = 0; // 给两个数组赋值
for (; i < Middle; ++i)
{
Array1[i] = Array[i];
}
for (int j = 0; j < ArrayLength - Middle; ++j)
{
Array2[j] = Array[i++];
}
MergeSort(Array1, Middle); // 递归调用 分割函数
MergeSort(Array2, ArrayLength - Middle); // ...
Merge(Array, Array1, Middle, Array2, ArrayLength - Middle); // 合并分割后的数组
delete[] Array1; // 删除新开辟的空间
delete[] Array2; // ...
};
MergeFun() 测试函数
void MergeFun()
{
int Array[] = { 0,3,4,7,9,8,2,1,6,5 };
int ArrayLength = sizeof(Array) / sizeof(Array[0]);
for (int i = 0; i < ArrayLength; ++i)
std::cout << Array[i] << " ";
std::cout << std::endl;
MergeSort(Array, ArrayLength);
for (int i = 0; i < ArrayLength; ++i)
std::cout << Array[i] << " ";
std::cout << std::endl;
};
希望大家多提程序优化和编程规范的意见 !!!