选择排序、冒泡排序、合并排序、快速排序、插入排序的算法思想和实现,以及时间复杂度比较。
以下排序算法均没有进行优化,而是采用最符合原始算法思想的方式进行实现和比较。
选择排序的思想与算法实现:
找出待排序的数列中的最小(或最大)元素,与待排序的数列的队首元素进行交换,队首元素并入已排序数列,直至待排数列的所有元素均已排完。
void SelectSort(int array[], int length){
int temp,key,i,j;
for(i = 0; i< length - 1; i++){
temp = i;
//遍历待排序数组,找到其中的最小值
for(j = i + 1; j < length; j++){
if(array[temp] > array[j])
temp = j;
}
//将最小值与当前指定元素交换
if(i != temp){
key = array[temp];
array[temp] = array[i];
array[i] = key;
}
}
}
T(n) = an² + bn + c
平均情况:O(n²)
最好情况:O(n²)
最坏情况:O(n²)
冒泡排序的思想与算法实现:
按顺序访问待排序的数列,一次比较两个相邻元素,如果他们的大小关系不对就交换他们的值,遍历一趟待排数列便会把待排数列中的最大(或最小值)移动到队末,将该最值并入已排数列,重复访问待排序直至待排数列中的元素均已排完。
void BubbleSort(int array[],int length){
int key,i,j;
for(i = 0; i < length; i++){
for(j = 0; j < length - i - 1; j++){
//当遍历到左边的数大于右边时,相邻两数进行交换
if(array[j] > array[j+1]){
key = array[j];
array[j] = array[j+1];
array[j+1] = key;
}
}
}
}
T(n) = an² + bn + c
平均情况:O(n²)
最好情况:O(n²)
最坏情况:O(n²)
合并排序的思想与算法实现:
将无序的数列分成两个无序子序列,再将所有无序子序列各分成两个无序子序列,直至所有子序列只含一个元素;将子序列合并成有序数列,相当于先分解再求解再合并。
合并操作需要创建或传递一个大小等于两个待合并序列之和的空序列,将两个待排子序列的队首元素进行比较,将较小的元素按顺序赋值给空序列,如果有一个子序列的元素全部赋值完,便将另一个子序列的所有值按顺序赋值给空序列。
void MergeSort(int array[], int length){
//创建等大数组用于合并子数列
int *array2 = new int[length];
if(array2 == NULL)
return ;
Mergesort(array, 0, length-1, array2);
delete array2;
}
void Mergesort(int array[], int first, int last, int array2[]){
//当数组元素大于1时,继续分成两个子序列
if(first < last){
int middle = (first + last)/2;
Mergesort(array, first, middle, array2);
Mergesort(array, middle+1, last, array2);
Merge(array, first, middle, last, array2);
}
}
void Merge(int array[], int first, int middle, int last, int array2[]){
int n1 = first, n2 = middle;
int m1 = middle + 1, m2 = last;
int i = 0,j = 0;
//将两个有序子序列按顺序合并到array2中
while(n1 <= n2 && m1 <= m2){
if(array[n1] < array[m1])
array2[i++] = array[n1++];
else
array2[i++] = array[m1++];
}
while(n1 <= n2)
array2[i++] = array[n1++];
while(m1 <= m2)
array2[i++] = array[m1++];
//将array2中的有序数列重新赋值会array
for(j = 0; j < i; j++)
array[first + j] = array2[j];
}
T(n) = 2T(n/2)+O(n)递推
= nlogn
平均情况:O(nlogn)
最好情况:O(nlogn)
最坏情况:O(nlogn)
快速排序的思想与算法实现:
将队首元素视为key,比key小的值移动到左边,比key大的值移动到右边,完成后以key为分界线将序列分成两个子序列,每个子序列再重复进行上诉操作直至排序完成,相当于先求部分解再分解。
void QuickSort(int array[], int low, int high)
{
//当待排数组只剩一个元素时,返回空
if(low >= high)
{
return;
}
int first = low;
int last = high;
int key = array[first];
while(first < last)
{
//将比key小的数移动到左边,比key大的移动到右边
while(first < last && array[last] >= key)
{
--last;
}
if(first
T(n) = 2T(n/2)+O(n)递推=aT(n/b)+D(n)+C(n)
= nlogn + n
平均情况:O(nlogn)
最好情况:O(nlogn)
最坏情况:O(n²)
插入排序的思想与算法实现:
从第二个元素开始,逆序与左边的元素依次做比较,直到遇到不比它大的元素,便将其插入到该元素后面,再从第三个元素开始循环,直至最后一个元素完成插入。
void InsertSort(int array[],int length) {
int key,i,j;
for (i = 1; i < length; i++) {
key = array[i];
j = i - 1;
//将key左边比它大的数往右移动,直到遇到第一个比key小的数
while (j > 0 && array[j] > key) {
array[j + 1] = array[j];
j = j - 1;
}
//将key插入到这个比它小的数的右边
array[j + 1] = key;
}
}
T(n) = an² + bn + c
平均情况:O(n²)
最好情况:O(n)
最坏情况:O(n²)
实际测试时间复杂度:快速排序 < 合并排序 < 插入排序< 选择排序< 冒泡排序。
win10+visual studio2015环境测试,int型数组
数组大小为10000-50000(纵坐标为时间单位us,表示所消耗的时间)
其中快速排序比合并排序快:
合并排序和快速排序都需要进行递归函数调用,但合并排序需要创建数组空间进行合并操作,快速排序只需在初始数组中进行交换赋值,所以合并排序的耗时比快速排序多。
数组大小为100、1000、10000、100000、100000。