排序算法总结
枚举思路下:直接插入排序、选择排序
递归思路下:归并排序、快速排序
插入排序是在一个已经有序的小序列的基础上,一次正确插入一个元素。
/***************直接插入排序算法***************
时间复杂度:最差o(n^2)
最好o(n)
稳定性: 稳定
***********************************************/
void InsertionSort(int *a,int n)
{
int i,j,key;
for(i=1;i<n;i++)
{
key = a[i];
j=i-1;
//1.寻找待插入的位置
while(j>=0 && key<a[j])
{
a[j+1]=a[j];
j--;
}
//![1]可替换过程1
//for(j=i-1;j>=0;j--)
//{
// if( key<a[j])
// a[j+1]=a[j];
// else break;
//}
//![1]
//2.插入
a[j+1]=key;
}
}
选择排序即是给每个位置选择待排序元素中当前最小的元素。
/***************选择排序算法*****************
时间复杂度:最好最差o(n^2)
稳定性: 不稳定
*********************************************/
void SelectionSort(int *a ,int n)
{
int i,j,min,pos;
for (i=0;i<n;i++)
{
//在位置i和之后的元素中查找最小值
min = a[i];
pos = i;
for (j=i+1;j<n;j++)
{
if (a[j]<min)
{
min=a[j];
pos=j;
}
}
//将最小的值与位置i的值交换,可导致不稳定
a[pos]=a[i];
a[i]=min;
}
}
归并排序是把序列递归地分成两个短序列,递归出口是短序列只有1个元素,然后把各个有序的段序列合并成一个有序的长序列,不断合并直到原序列全部排好序。
/*************************归并排序***********************
时间复杂度:最好最差o(nlogn)
稳定性 : 稳定
注意:array[start_idx,end_idx)是左闭右开区间
*********************************************************/
void MergeSort(int *array,int start_idx,int end_idx)
{
int n = end_idx - start_idx ;
if (n == 1) return;
//按原始数组长度为临时数组分配空间
int *tmp = new int[n];
int mid_idx = n/2 + start_idx;
//1.拆分,对子数组进行排序
MergeSort(array,start_idx,mid_idx);
MergeSort(array,mid_idx,end_idx);
//2.合并子数组
int idx = 0,j = start_idx, k = mid_idx;
while( (j<mid_idx )&&(k<end_idx ))
{
if(array[j] < array[k])
tmp[idx++] = array[j++];
else tmp[idx++] = array[k++];
}
while(j < mid_idx)
tmp[idx++] = array[j++];
while(k < end_idx)
tmp[idx++] = array[k++];
//3.从临时数组中将数据保存到原数组
for (int i = 0, m = start_idx ; i < n ;i++, m++)
array[m] = tmp[i];
//![3]
//int i=0,m=start_idx;
//while(i<n) array[m++] = tmp[i++];
//![3]
//释放空间
delete[] tmp;
}
快速排序通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
/*****************快速排序********************
时间复杂度:最好o(nlogn)
最差o(n^2)
稳定性 :不稳定
**********************************************/
void QuickSort(int *array,int len)
{
if (len<=1) return;
//按最坏的可能为两个数组分配空间
int *left = new int[len], *right = newint[len];
//设置两个子数组的初始长度为0
int left_idx=0,right_idx=0;
//1.拆分
int key = array[0];
for (int i=1;i<len;i++)
{
if (array[i]<key)
left[left_idx++] = array[i];
if (array[i]>=key)
right[right_idx++] = array[i];
}
//2.对子数组进行排序
QuickSort(left,left_idx);
QuickSort(right,right_idx);
//3.合并子数组
int idx = 0;
for (int i=0;i<left_idx;i++)
array[idx++] = left[i];
array[idx++] = key;
for (int i=0;i<right_idx;i++)
array[idx++] = right[i];
//释放空间
delete[] left;
delete[] right;
}