目录
介绍
插入排序
直接插入排序是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好的有序的表中,从而得到一个新的、记录数增1的有序表。
当前元素的前面元素均为有序,要插入时,从当前元素的左边开始往前找(从后往前找),比当前元素大的元素均往右移一个位置,最后把当前元素放在它应该呆的位置就行了。
时间复杂度O(N^2)
二分插入排序
插入排序方式首先需要为要插入的元素找到插入序列中合适的插入位置。通过折半((low+high)/2=mid)的方式,凭借一个mid来使得我们通过二分插入区的方式,不断缩小插入的区域,直到low>high时,我们即可找到元素的插入位置high+1。此种方式在时间复杂度上仍和直接插入排序算法处于同一个等级,但由于使用了折半的方式,所以在为插入元素寻找插入位置时会更加高效(尤其在数据量较大时)。
时间复杂度:最坏情况(整个序列逆序时)时间复杂度为O(n2),最优情况(整个序列初始顺序,从大到小时)时间复杂度为O(nlog2n),平均情况时间复杂度为O(n2)。
希尔排序
是一种插入排序改进算法,对于大规模乱序数组插入排序很慢,因为它只会交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另一端。假如,如果主键最小的元素正好在数组的尽头,要将它挪到正确的位置就需要N-1次移动。希尔排序为了加快速度简单的改进了插入排序,交换不相邻的元素对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
时间复杂度O(n^(1.3—2))
冒泡排序
依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。时间复杂度O(n^2)
快排
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
- 首先设定一个分界值,通过该分界值将数组分成左右两部分。
- 将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
- 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
- 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
时间复杂度O (nlogn)
选择排序
第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。时间复杂度O(n^2)
堆排序
是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
- 构建初始堆,将待排序列构成一个大顶堆(或者小顶堆),升序大顶堆,降序小顶堆;
- 将堆顶元素与堆尾元素交换,并断开(从待排序列中移除)堆尾元素。
- 重新构建堆。
- 重复2~3,直到待排序列中只剩下一个元素(堆顶元素)。
时间复杂度:O(nlogn)
归并排序
归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
例如:
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
时间复杂度:O(nlogn)
基数排序
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度度为O (nlog(r)m),其中r为所采取的基数,而m为堆数。
假设原来有一串数值如下所示:
73, 22, 93, 43, 55, 14, 28, 65, 39, 81
第一步:
首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
0
1 81
2 22
3 73 93 43
4 14
5 55 65
6
7
8 28
9 39
第二步:
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
81, 22, 73, 93, 43, 14, 55, 65, 28, 39
接着再进行一次分配,这次是根据十位数来分配:
0
1 14
2 22 28
3 39
4 43
5 55
6 65
7 73
8 81
9 93
第三步:
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
14, 22, 28, 39, 43, 55, 65, 73, 81, 93
这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。
代码实现:
#include "Data.h"
#include "LinkQueue.h"
template<typename Type> class Sort
{
public:
void InsertSort(DataList<Type>& list, int n = -1);
void BinaryInsertSort(DataList<Type>& list, int n = -1);
void ShellSort(DataList<Type>& list, const int gap = -1);
void BubbleSort(DataList<Type>& list);
void QuickSort(DataList<Type>& list, int left = 0, int right = -3);
void SelectSort(DataList<Type>& list);
void HeapSort(DataList<Type>& list);
void MergeSort(DataList<Type>& list);
void RadixSort(DataList<int>& list, int m, int d); //just use for integer!
private:
void BubbleSwap(DataList<Type>& list, const int n, int& flag);
void SelectChange(DataList<Type>& list, const int n);
void HeapAdjust(DataList<Type>& list, const int start, const int end);
void Merge(DataList<Type>& list, DataList<Type>& mergedlist, const int len);
void MergeDouble(DataList<Type>& list, DataList<Type>& mergedlist, const int start, const int part, const int end);
};
template<typename Type> void Sort<Type>::InsertSort(DataList<Type>& list, int n)
{
if (-1 == n)
{
for (int i = 1; i < list.m_ncurrentsize; i++)
{
InsertSort(list, i);
}
return;
}
Element<Type> temp = list.m_pvector[n];
int i;
for (i = n; i > 0; i--)
{
if (temp > list.m_pvector[i - 1])
{
break;
}
else
{
list.m_pvector[i] = list.m_pvector[i - 1];
}
}
list.m_pvector[i] = temp;
}
template<typename Type> void Sort<Type>::BinaryInsertSort(DataList<Type>& list, int n)
{
if (-1 == n)
{
for (int i = 1; i < list.m_ncurrentsize; i++)
{
BinaryInsertSort(list, i);
}
return;
}
Element<Type> temp = list.m_pvector[n];
int left = 0, right = n - 1;
while (left <= right)
{
int middle = (left + right) / 2;
if (temp < list.m_pvector[middle])
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
for (int i = n - 1; i >= left; i--)
{
list.m_pvector[i + 1] = list.m_pvector[i];
}
list.m_pvector[left] = temp;
}
template<typename Type> void Sort<Type>::ShellSort(DataList<Type>& list, const int gap)
{
if (-1 == gap)
{
int gap = list.m_ncurrentsize / 2;
while (gap)
{
ShellSort(list, gap);
gap = (int)(gap / 2);
}
return;
}
for (int i = gap; i < list.m_ncurrentsize; i++)
{
InsertSort(list, i);
}
}
template<typename Type> void Sort<Type>::BubbleSwap(DataList<Type>& list, const int n, int& flag)
{
flag = 0;
for (int i = list.m_ncurrentsize - 1; i >= n; i--)
{
if (list.m_pvector[i - 1] > list.m_pvector[i])
{
list.Swap(list.m_pvector[i - 1], list.m_pvector[i]);
flag = 1;
}
}
}
template<typename Type> void Sort<Type>::BubbleSort(DataList<Type>& list)
{
int flag = 1, n = 0;
while (++n < list.m_ncurrentsize && flag)
{
BubbleSwap(list, n, flag);
}
}
template<typename Type> void Sort<Type>::QuickSort(DataList<Type>& list, int left = 0, int right = -3)
{
if ( -3 == right)
{
right = list.m_ncurrentsize - 1;
}
if (left < right)
{
int pivotpos = left;
Element<Type> pivot = list.m_pvector[left];
for (int i = left + 1; i <= right; i++)
{
if (list.m_pvector[i] < pivot && ++pivotpos != i)
{
list.Swap(list.m_pvector[pivotpos], list.m_pvector[i]);
}
}
list.Swap(list.m_pvector[left], list.m_pvector[pivotpos]);
QuickSort(list, left, pivotpos - 1);
QuickSort(list, pivotpos + 1, right);
}
}
template<typename Type> void Sort<Type>::SelectChange(DataList<Type>& list, const int n)
{
int j = n;
for (int i = n + 1; i < list.m_ncurrentsize; i++)
{
if (list.m_pvector[i] < list.m_pvector[j])
{
j = i;
}
}
if (j != n)
{
list.Swap(list.m_pvector[n], list.m_pvector[j]);
}
}
template<typename Type> void Sort<Type>::SelectSort(DataList<Type>& list)
{
for (int i = 0; i < list.m_ncurrentsize - 1; i++)
{
SelectChange(list, i);
}
}
template<typename Type> void Sort<Type>::HeapAdjust(DataList<Type>& list, const int start, const int end)
{
int current = start, child = 2 * current + 1;
Element<Type> temp = list.m_pvector[start];
while (child <= end)
{
if (child < end && list.m_pvector[child] < list.m_pvector[child + 1])
{
child++;
}
if (temp >= list.m_pvector[child])
{
break;
}
else
{
list.m_pvector[current] = list.m_pvector[child];
current = child;
child = 2 * current + 1;
}
}
list.m_pvector[current] = temp;
}
template<typename Type> void Sort<Type>::HeapSort(DataList<Type>& list)
{
for (int i = (list.m_ncurrentsize - 2) / 2; i >= 0; i--)
{
HeapAdjust(list, i, list.m_ncurrentsize - 1);
}
for (int i = list.m_ncurrentsize - 1; i >= 1; i--)
{
list.Swap(list.m_pvector[0], list.m_pvector[i]);
HeapAdjust(list, 0, i - 1);
}
}
template<typename Type> void Sort<Type>::MergeDouble(DataList<Type>& list, DataList<Type>& mergedlist, const int start, const int part, const int end)
{
int i = start, j = part + 1, k = start;
while (i <= part && j <= end)
{
if (list.m_pvector[i] <= list.m_pvector[j])
{
mergedlist.m_pvector[k++] = list.m_pvector[i++];
}
else
{
mergedlist.m_pvector[k++] = list.m_pvector[j++];
}
}
if (i <= part)
{
for (int m = i; m <= part && k <= end;)
{
mergedlist.m_pvector[k++] = list.m_pvector[m++];
}
}
else
{
for (int m = j; m <= end && k <= end; m++)
{
mergedlist.m_pvector[k++] = list.m_pvector[m];
}
}
}
template<typename Type> void Sort<Type>::Merge(DataList<Type>& list, DataList<Type>& mergedlist, const int len)
{
int n = 0;
while (n + 2 * len < list.m_ncurrentsize)
{
MergeDouble(list, mergedlist, n, n + len - 1, n + 2 * len - 1);
n += 2 * len;
}
if (n + len < list.m_ncurrentsize)
{
MergeDouble(list, mergedlist, n, n + len - 1, list.m_ncurrentsize - 1);
}
else
{
for (int i = n; i < list.m_ncurrentsize; i++)
{
mergedlist.m_pvector[i] = list.m_pvector[i];
}
}
}
template<typename Type> void Sort<Type>::MergeSort(DataList<Type>& list)
{
DataList<Type> temp(list.m_nMaxSize);
temp.m_ncurrentsize = list.m_ncurrentsize;
int len = 1;
while (len < list.m_ncurrentsize)
{
Merge(list, temp, len);
len *= 2;
Merge(temp, list, len);
len *= 2;
}
}
template<typename Type> void Sort<Type>::RadixSort(DataList<int>& list, int m, int d)
{
LinkQueue<int>* queue = new LinkQueue<int>[d];
int power = 1;
for (int i = 0; i < m; i++)
{
if (i)
{
power = power * d;
}
for (int j = 0; j < list.m_ncurrentsize; j++)
{
int k = (list.m_pvector[j].GetKey() / power) % d;
queue[k].Append(list.m_pvector[j].GetKey());
}
for (int j = 0, k = 0; j < d; j++)
{
while (!queue[j].IsEmpty())
{
list.m_pvector[k++].SetKey(queue[j].Delete());
}
}
}
}
main.cpp
#include <iostream>
using namespace std;
#define totalCout 50000
#include "Sort.h"
#include <time.h>
int* generateRandomArray(int n, int rangeL, int rangeR)
{
int* arr = new int[n]; // 创建一个 n个元素的数组
srand(time(NULL)); // 随机种子
for (int i = 0; i < n; i++)
arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
return arr;
}
int main()
{
int* init = generateRandomArray(totalCout, 0, totalCout);
DataList<int> data(init, totalCout);
Sort<int> sort;
//data.Print(-1);
cout << endl << endl << endl;
auto startTime = clock();//计时开始
sort.InsertSort(data);
auto endTime = clock();//计时结束
cout << "The run time InsertSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data.Print(0);
DataList<int> data1(init, totalCout);
startTime = clock();//计时开始
sort.BinaryInsertSort(data1);
endTime = clock();//计时结束
cout << "The run time BinaryInsertSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data1.Print(1);
DataList<int> data2(init, totalCout);
startTime = clock();//计时开始
sort.ShellSort(data2);
endTime = clock();//计时结束
cout << "The run time ShellSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data2.Print(2);
DataList<int> data3(init, totalCout);
startTime = clock();//计时开始
sort.BubbleSort(data3);
endTime = clock();//计时结束
cout << "The run time BubbleSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data3.Print(3);
DataList<int> data4(init, totalCout);
auto startTime = clock();//计时开始
sort.QuickSort(data4);
auto endTime = clock();//计时结束
cout << "The run time QuickSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data4.Print(4);
DataList<int> data5(init, totalCout);
startTime = clock();//计时开始
sort.SelectSort(data5);
endTime = clock();//计时结束
cout << "The run time SelectSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data5.Print(5);
DataList<int> data6(init, totalCout);
startTime = clock();//计时开始
sort.HeapSort(data6);
endTime = clock();//计时结束
cout << "The run time HeapSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data6.Print(6);
DataList<int> data7(init, totalCout);
startTime = clock();//计时开始
sort.MergeSort(data7);
endTime = clock();//计时结束
cout << "The run time MergeSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data7.Print(7);
DataList<int> data8(init, totalCout);
startTime = clock();//计时开始
sort.RadixSort(data8, 5, 10);
endTime = clock();//计时结束
cout << "The run time RadixSort is : " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s\n" << endl;
//data8.Print(8);
return 0;
}
性能比较:
随机产生5万条数据,排序耗时如下:
为什么选5万条,是因为对于那些算法复杂度为O(n^2)的来见,10万以上的数据我的小笔记本已经跑不动了,但是只要屏蔽掉那些算法复杂度O(n^2)的代码,就可以测试千万条数据排序时间。
屏蔽掉那些蔽掉那些算法复杂度O(n^2)的代码,测试1千万条数据的排序时间: