目录
排序:假设有n个记录的序列{r1,r2,...rn},其相应的关键字分别为{k1,k2,...kn},需确定1,2,....,n的一种排列p1,p2,......pn,使其相应的关键字满足非递减或非递增关系,即使得序列成为一个按关键字有序的序列,这样的操作即为排序。
根据在排序过程中待排序的记录是否全部放在内存中,分为内排序和外排序。内排序主要受时间性能、辅助空间和算法复杂性实现的。
按照算法复杂度将排序分为两大类,即
(1)简单算法:冒泡排序、简单选择排序、插入排序 ;
(2)改进算法:希尔排序、堆排序、归并排序、快速排序 ;
1.冒泡排序
冒泡排序:一种交换排序。基本思想是,两两比较相邻记录关键字,如果反序交换,直到没有反序的记录为止。
如果待排序的序列为{2,1,3,4,5,6,7,8,9}时,如果仍遍历所有,进行比较,则作了很多无用功。因此需要改进一下,增加标记变量flag来实现算法改进。
//02冒泡排序算法
void sortMethod02(Data *list)
{
bool flag = true;
for (int i = 1;i <= list->length&&flag;i++)
{
flag = false;
for (int j = list->length-1; j >= i; j--)
{
if (list->r[j]<list->r[j-1])
{
swap(list, j, j - 1);
flag = true;
}
}
}
}
2.简单选择排序
简单选择排序:通过次关键字间的比较,从个记录中选出最小的关键字,并和第个记录交换之。
简单选择排序的性能上略优于冒泡排序。
//03简单选择排序算法
void sortMethod03(Data *list)
{
int min;
for (int i = 1; i <= list->length; i++)
{
min = i;
for (int j = i+1; j <= list->length; j++)
{
if (list->r[min] > list->r[j])
{
min = j;
}
}
if (min != i)
{
swap(list, i, min);
}
}
}
3.直接插入排序算法
直接插入排序算法:将一个数字插入到已经排好序的有序表中,从而得到一个新的,记录增加1的有序表。
直接插入排序法比冒泡和简单选择排序性能要好一些。
直接插入排序在下列两种情况比较有优势:
(1)序列本身基本有序,只需要少量的插入操作,就可以完成整个序列的排序工作;
(2)序列内数字个数比较;
//04 直接插入排序
void sortMethod04(Data *list)
{
int j;
for (int i = 2; i <= list->length; i++)
{
if (list->r[i]<list->r[i-1])
{
list->r[0] = list->r[i];//r[0]为哨兵位置
for (j = i-1;list->r[j]>list->r[0]; j--)
{
list->r[j + 1] = list->r[j];
}
list->r[j + 1] = list->r[0];
}
}
}
4.希尔排序
希尔排序:首先将整个序列中相距某个“增量”的记录组成多个子序列,然后在各个子序列中分别进行直接插入排序,从而得到基本有序的序列,再对整个序列进行一次直接插入排序。其特点为跳跃式移动,而非一步一步往前挪动。
针对希尔排序的说明:
(1)“增量”的选取非常关键,迄今为止,还没有找到一种最好的增量序列。但研究表明,当序列为时,可以获得不错的效果;“增量”数列的最后一个增量值必须等于1才行。
(2)基本有序:小的关键字基本在前面,大的基本在后面,不大不小的基本在中间。
//05 希尔排序
void sortMethod05(Data *list)
{
int i, j;
int delta = list->length;
do
{
delta = delta / 3 + 1;
for ( i = delta+1; i <= list->length; i++)
{
if (list->r[i]<list->r[i-delta])
{
list->r[0] = list->r[i];
for ( j = i-delta; j>0&&list->r[0]<list->r[j]; j-=delta)
{
list->r[j + delta] = list->r[0];
}
list->r[j + delta] = list->r[0];
}
}
} while (delta>1);
}
5. 堆排序
堆排序:利用堆进行排序的方法。
基本思想:将待排序的序列后成一个大顶堆。此时,整个序列最大值就是堆顶的根节点。将它移走(即与对数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的个序列重新构成一个大顶堆,这样就会得到个元素中的次大值。如此反复执行,便得到一个有序序列。
关键步骤:(1)由无序序列构建堆。(2)在输出堆顶元素后,调整剩余元素生成一个新的堆。
特点:堆排序性能远远好过于冒泡、简单选择、直接插入的时间复杂度。
堆排序是一种不稳定的排序方法。
由于初始构建堆需要比较次数较多,因此,并不适合排序序列个数较少的情况。
//06 堆排序
void createHeap(Data *list, int begin, int end);
void sortMethod06(Data *list)
{
for (int i = 1; i <= (list->length)/2; i++)
{
createHeap(list,i,list->length);
}
for (int i = list->length; i >1; i--)
{
swap(list, 1, i);
createHeap(list, 1, i - 1);
}
}
void createHeap(Data *list, int begin, int end)
{
int temp, j;
temp = list->r[begin];
for ( j = 2*begin; j <= end; j*=2)
{
if (j < end&&list->r[j] < list->r[j + 1])
++j;
if (temp >= list->r[j])
break;
list->r[begin] = list->r[j];
begin = j;
}
list->r[begin] = temp;
}
6.归并排序
归并排序:就是利用归并的思想。
2路归并排序:假设初始序列含有n个记录,则可以看成是有n个有序的子序列,每个子序列的长度为1,然后两两归并,得到([x]表示不小x的最小整数)个长度为2或1的有序子序列;再两两归并,...,如此重复,直至得到一个长度为n的有序序列位置。这种排序方法为2路归并排序。
void MSort(int SR[],int TR1[],int s,int t);
void Merge(int SR[], int TR1[], int i, int m, int n);
void sortMethod07(Data *list)
{
MSort(list->r, list->r, 1, list->length);
}
void MSort(int SR[], int TR1[], int s, int t)
{
int m;
int TR2[MaxSize + 1];
if (s==t)
{
TR1[s] = SR[s];
}
else
{
m = (s + t) / 2;
MSort(SR, TR2, s, m);
MSort(SR, TR2, m+1, t);
Merge(TR2, TR1, s, m, t);
}
}
void Merge(int SR[], int TR[], int i, int m, int n)
{
int j, k, l;
for (j=m+1,k=i ; i <=m &&j<=n; k++)
{
if (SR[i] < SR[j])
TR[k] = SR[i++];
else
TR[k] = SR[j++];
}
if (i<=m)
{
for ( l = 0; l <= m-i; l++)
{
TR[k + l] = SR[i + 1];
}
}
if (j <= n)
{
for (l = 0; l <= n - j; l++)
{
TR[k + l] = SR[j + 1];
}
}
}
7.快速排序
快速排序:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
void QSort(Data *list, int low, int high);
int Partition(Data *list, int low, int high);
void sortMethod08(Data *list)
{
QSort(list,1,list->length);
}
void QSort(Data *list, int low, int high)
{
int pivot;
if (low<high)
{
pivot = Partition(list, low, high);
QSort(list, low, pivot - 1);
QSort(list, high, high);
}
}
int Partition(Data *list, int low, int high)
{
int pivotkey;
pivotkey = list->r[low];
while (low < high)
{
while (low<high&&list->r[high]>=pivotkey)
{
high--;
}
swap(list, low, high);
while (low < high&&list->r[low] <= pivotkey)
low++;
swap(list, low, high);
}
return low;
}
8. 总结与算法时间复杂度分析
以上为七大排序方法,主要归属于插入排序、交换排序、选择排序和归并排序四类。
排序 | |||||||
插入排序类 | 选择排序类 | 交换排序类 | 归并排序类 | ||||
直接插入 排序 | 希尔排序 | 简单选择排序 | 堆排序 | 冒泡排序 | 快速排序 | 归并排序 |
上述算法的时间复杂度对比
排序方式 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
冒泡排序 | 稳定 | ||||
简单选择排序 | 稳定 | ||||
直接插入排序 | 稳定 | ||||
希尔排序 | ~ | 不稳定 | |||
堆排序 | 不稳定 | ||||
归并排序 | 稳定 | ||||
快速排序 | ~ | 不稳定 |
附录
附上所有代码:
//七大排序
#include<iostream>
using namespace std;
#define MaxSize 10 //待排序个数
struct Data
{
int r[MaxSize + 1];//取多出的一个作为临时变量
int length;
};
void swap(Data *list, int i, int j)
{
int temp = list->r[i];
list->r[i] = list->r[j];
list->r[j] = temp;
}
//01最简单的排序
void sortMethod01(Data *list)
{
for (int i = 1; i <= list->length; i++)
{
for (int j = i + 1; j <= list->length; j++)
{
if (list->r[i] > list->r[j])
{
swap(list, i, j);
}
}
}
}
//02冒泡排序算法
void sortMethod02(Data *list)
{
bool flag = true;
for (int i = 1;i <= list->length&&flag;i++)
{
flag = false;
for (int j = list->length-1; j >= i; j--)
{
if (list->r[j]<list->r[j-1])
{
swap(list, j, j - 1);
flag = true;
}
}
}
}
//03简单选择排序算法
void sortMethod03(Data *list)
{
int min;
for (int i = 1; i <= list->length; i++)
{
min = i;
for (int j = i+1; j <= list->length; j++)
{
if (list->r[min] > list->r[j])
{
min = j;
}
}
if (min != i)
{
swap(list, i, min);
}
}
}
//04 直接插入排序
void sortMethod04(Data *list)
{
int j;
for (int i = 2; i <= list->length; i++)
{
if (list->r[i]<list->r[i-1])
{
list->r[0] = list->r[i];
for (j = i-1;list->r[j]>list->r[0]; j--)
{
list->r[j + 1] = list->r[j];
}
list->r[j + 1] = list->r[0];
}
}
}
//05 希尔排序
void sortMethod05(Data *list)
{
int i, j;
int delta = list->length;
do
{
delta = delta / 3 + 1;
for ( i = delta+1; i <= list->length; i++)
{
if (list->r[i]<list->r[i-delta])
{
list->r[0] = list->r[i];
for ( j = i-delta; j>0&&list->r[0]<list->r[j]; j-=delta)
{
list->r[j + delta] = list->r[0];
}
list->r[j + delta] = list->r[0];
}
}
} while (delta>1);
}
//06 堆排序
void createHeap(Data *list, int begin, int end);
void sortMethod06(Data *list)
{
for (int i = 1; i <= (list->length)/2; i++)
{
createHeap(list,i,list->length);
}
for (int i = list->length; i >1; i--)
{
swap(list, 1, i);
createHeap(list, 1, i - 1);
}
}
void createHeap(Data *list, int begin, int end)
{
int temp, j;
temp = list->r[begin];
for ( j = 2*begin; j <= end; j*=2)
{
if (j < end&&list->r[j] < list->r[j + 1])
++j;
if (temp >= list->r[j])
break;
list->r[begin] = list->r[j];
begin = j;
}
list->r[begin] = temp;
}
//07 归并排序-递归方法
void MSort(int SR[],int TR1[],int s,int t);
void Merge(int SR[], int TR1[], int i, int m, int n);
void sortMethod07(Data *list)
{
MSort(list->r, list->r, 1, list->length);
}
void MSort(int SR[], int TR1[], int s, int t)
{
int m;
int TR2[MaxSize + 1];
if (s==t)
{
TR1[s] = SR[s];
}
else
{
m = (s + t) / 2;
MSort(SR, TR2, s, m);
MSort(SR, TR2, m+1, t);
Merge(TR2, TR1, s, m, t);
}
}
void Merge(int SR[], int TR[], int i, int m, int n)
{
int j, k, l;
for (j=m+1,k=i ; i <=m &&j<=n; k++)
{
if (SR[i] < SR[j])
TR[k] = SR[i++];
else
TR[k] = SR[j++];
}
if (i<=m)
{
for ( l = 0; l <= m-i; l++)
{
TR[k + l] = SR[i + 1];
}
}
if (j <= n)
{
for (l = 0; l <= n - j; l++)
{
TR[k + l] = SR[j + 1];
}
}
}
//08 快速排序
void QSort(Data *list, int low, int high);
int Partition(Data *list, int low, int high);
void sortMethod08(Data *list)
{
QSort(list,1,list->length);
}
void QSort(Data *list, int low, int high)
{
int pivot;
if (low<high)
{
pivot = Partition(list, low, high);
QSort(list, low, pivot - 1);
QSort(list, high, high);
}
}
int Partition(Data *list, int low, int high)
{
int pivotkey;
pivotkey = list->r[low];
while (low < high)
{
while (low<high&&list->r[high]>=pivotkey)
{
high--;
}
swap(list, low, high);
while (low < high&&list->r[low] <= pivotkey)
low++;
swap(list, low, high);
}
return low;
}
//01最简单的排序调用
void Test01(Data *list)
{
sortMethod01(list);
cout << "最简单的排序调用结果为:" << endl;
for (int i = 1; i <= list->length; i++)
{
cout << list->r[i] << " ";
}
cout << endl;
}
//02冒泡排序调用
void Test02(Data *list)
{
sortMethod02(list);
cout << "冒泡排序调用结果为:" << endl;
for (int i = 1; i <= list->length; i++)
{
cout << list->r[i] << " ";
}
cout << endl;
}
//03简单选择排序调用
void Test03(Data *list)
{
sortMethod03(list);
cout << "简单选择排序调用结果为:" << endl;
for (int i = 1; i <= list->length; i++)
{
cout << list->r[i] << " ";
}
cout << endl;
}
//04直接插入排序调用
void Test04(Data *list)
{
sortMethod04(list);
cout << "简单选择排序调用结果为:" << endl;
for (int i = 1; i <= list->length; i++)
{
cout << list->r[i] << " ";
}
cout << endl;
}
//05 希尔排序
void Test05(Data *list)
{
sortMethod05(list);
cout << "希尔排序调用结果为:" << endl;
for (int i = 1; i <= list->length; i++)
{
cout << list->r[i] << " ";
}
cout << endl;
}
//06 堆排序
void Test06(Data *list)
{
sortMethod06(list);
cout << "堆排序调用结果为:" << endl;
for (int i = 1; i <= list->length; i++)
{
cout << list->r[i] << " ";
}
cout << endl;
}
//07 归并排序
void Test07(Data *list)
{
sortMethod07(list);
cout << "归并排序调用结果为:" << endl;
for (int i = 1; i <= list->length; i++)
{
cout << list->r[i] << " ";
}
cout << endl;
}
//08 快速排序
void Test08(Data *list)
{
sortMethod08(list);
cout << "快速排序调用结果为:" << endl;
for (int i = 1; i <= list->length; i++)
{
cout << list->r[i] << " ";
}
cout << endl;
}
int main()
{
//初始化
Data list =
{ { 0,9,1,5,8,3,7,4,6,2 },
9
};
//test
Test01(&list);
Test02(&list);
Test03(&list);
Test04(&list);
Test05(&list);
Test06(&list);
Test07(&list);
Test08(&list);
cin.get();
system("pause");
}