常用的排序算法总结
插入排序
时间复杂度:O(n^2)
实现思路:
(1) 设置基准数a[0],将待插入纪录的值赋值给a[0];
(2) 设置开始查找的位置moveInd;
(3) 在数组中进行搜索,搜索中将第moveInd个纪录后移,直至a[0].value≥a[moveInd].value为止;
(4) 将a[0]插入a[moveInd+1]的位置上。
/******************************************************************
@function: ascending order sort
@param: a:array first address. len:array elements,you can get for sizeof(a)/sizeof(a[0])
@return:
*******************************************************************/
void InsertSort(int*a,int length)
{
for (int index=1;index<length;index++)
{
int moveInd=index-1;
int afterVal = a[index];
while ( moveInd>=0 && a[moveInd]>afterVal ) //moveInd can't over index&
{
a[moveInd+1] = a[moveInd]; //move
moveInd--;
}
a[moveInd+1] = afterVal;
}
}
选择排序
时间复杂度:O(n^2)
实现思路:
(1) 从a数组下标index=0开始遍历数组;
(2) 在(1)的遍历循环中将最小(大)的元素下标(beforeInd);
(3)before判断是否大于index,大于则下标为before和index-1(相当于起始位置)交换元素,反之。
/******************************************************************
@function: ascending order sort
@param: a:array first address. len:array elements,you can get for sizeof(a)/sizeof(a[0])
@return:
*******************************************************************/
void SelectSort(int*a,int len)
{
int index,afterInd,beforeInd;
for (index=0;index<len-1;index++)
{
for (afterInd=index+1,beforeInd=index;afterInd<len;afterInd++)
{
if (a[afterInd]<a[beforeInd]) //find min
beforeInd=afterInd;
}
if (beforeInd>index) //swap value
SWAP(a[index],a[beforeInd]);
}
}
冒泡排序
时间复杂度:O(n^2)
实现思路:
(1) 构造两重循环,第一层循环(i值下标)遍历到数组倒数第二个数,第二层循环在i值的基础上遍历剩余下标的数
(2)在第二层循环中将当前循环所涉及到的最小值交换移动到前列。
/******************************************************************
@function: ascending order sort
@param: a:array first address. len:array elements,you can get for sizeof(a)/sizeof(a[0])
@return:
*******************************************************************/
void BubbletSort(int*a,int len)
{
for(int i=0;i<len-1;i++)
for(int j=i+1;j<len;j++)
{
if(a[i]>a[j])
{
SWAP(a[i],a[j]);
}
}
}
堆排序
时间复杂度:O(nlog n)
实现思路:
(1) 从a数组下标index=0开始遍历数组;
(2) 在(1)的遍历循环中将最小(大)的元素下标(beforeInd);
(3)before判断是否大于index,大于则下标为before和index-1(相当于起始位置)交换元素,反之。
/******************************************************************
@function: tree make-up
@param:
@return:
*******************************************************************/
void HeapAdjust(int *a,int rootIndex,int len)
{
int childIndex;
for(;2*rootIndex+1<len;rootIndex=childIndex)//出口是树的结点越界
{
//子结点的位置=2*(父结点位置)+1
childIndex=2*rootIndex+1;
//得到子结点中较大的结点
if(childIndex<len-1 && a[childIndex+1]>a[childIndex])
{
childIndex++;
}
//如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点
if(a[rootIndex]<a[childIndex])
{
SWAP(a[rootIndex],a[childIndex]);
}
else
{
break; //否则退出循环
}
}
}
/******************************************************************
@function: heap sort
@param: a:array first address. len:array elements,you can get for sizeof(a)/sizeof(a[0])
@return:
*******************************************************************/
void HeapSort(int*a,int len) //算法主体函数
{
//调整序列的前半部分元素,调整完之后第一个元素是序列的最大的元素
//length/2-1是最后一个非叶节点,此处"/"为整除
for(int i=len/2-1;i>=0;i--) /**构建完全树*/
HeapAdjust(a,i,len);
/**将完全树进行排序*/
while(--len)
{
//第一个元素和当前的最后一个元素交换,
//保证当前的最后一个位置的元素都是在现在的这个序列之中最大的
SWAP(a[0],a[len]);
//不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值
HeapAdjust(a,0,len);
}
}
归并排序
时间复杂度:O(nlog n)
实现思路:
(1) 该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,归并排序将两个已排序的表合并成一个表。
(2)设两个有序的子序列(相当于输入序列)放在同一序列中相邻的位置上:array[low…m],array[m + 1…high],先将它们合并到一个局部的暂存序列 temp (相当于输出序列)中,待合并完成后将 temp 复制回 array[low…high]中,从而完成排序。
(3)在具体的合并过程中,设置 i,j 和 p 三个指针,其初值分别指向这三个记录区的起始位置。合并时依次比较 array[i] 和 array[j] 的关键字,取关键字较小(或较大)的记录复制到 temp[p] 中,然后将被复制记录的指针 i 或 j 加 1,以及指向复制位置的指针 p加 1。重复这一过程直至两个输入的子序列有一个已全部复制完毕(不妨称其为空),此时将另一非空的子序列中剩余记录依次复制到 array 中即可。
例子
待排序列(14,12,15,13,11,16)
####假设我们有一个没有排好序的序列,那么首先我们使用分割的办法将这个序列分割成一个个已经排好序的子序列。然后再利用归并的方法将一个个的子序列合并成排序好的序列。分割和归并的过程可以看下面的图例。
###先分割再合并