一、插入排序-直接插入排序(Straight Insertion Sort)
直接插入排序(Straight Insertion Sort)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表。开始时有序表中只包含1个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。
#include
using namespacestd;void InsertSort(int *a,intn)
{for(int i=1;i
{if(a[i]
{int j=i-1;int x=a[i];
a[i]=a[i-1];while(x
a[j]=x;
}
}
}intmain()
{int a[8]={-3,-1,-5,-7,-2,-4,-9,-6};
InsertSort(a,8);for(int i=0;i<8;i++)
printf("%d%c",a[i],i==7?'\n':' ');return 0;
}
二、插入排序-希尔排序(Shell's Sort)
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
如-3,-1,-5,-7,-2,-4,-9,-6
第一次分组k=8/2=4,分为四组(-3,-2)(-1,-4)(-5,-9)(-7,-6)排序后为-3,-4,-9,-7,-2,-1,-5,-6;第二次k=4/2=2
分为两组(隔二取一)(-3,-9,-2,-5)(-4,-7,-1,-6)
-9,-7,-5,-6,-3,-4,-2,-1
第二次 k=1,整体为一组,直接插序。
#include
using namespacestd;void ShellSort(int *a,intn)
{for(int k=n/2;k;k/=2)
{for(int i=k;i
{for(int j=i-k;j>=0;j-=k)if(a[j]>a[j+k]) swap(a[j],a[j+k]);
}
}
}intmain()
{int a[8]={-3,-1,-5,-7,-2,-4,-9,-6};
ShellSort(a,8);for(int i=0;i<8;i++)
printf("%d%c",a[i],i==7?'\n':' ');return 0;
}
三、选择排序-简单选择排序(Simple Selection Sort)
选则排序,和插入排序不同的是,每次从数组中选择一个最小的数,放到前面,因此就是n次循环O(n^2)
void SelectionSort(int *a,intn)
{for(int i=0;i
{int k=i;for(int j=i+1;j
}
}intmain()
{int a[8]={-3,-1,-5,-7,-2,-4,-9,-6};
SelectionSort(a,8);for(int i=0;i<8;i++)
printf("%d%c",a[i],i==7?'\n':' ');return 0;
}
上面的选择排序,每次确定一个最小值,循环n次,也可以二元选择,每次确定一个最大值,一个最小值,因此可以减少循环。
//二元选择排序
#include
using namespacestd;void SelectionSort_TwoPoint(int *a,intn)
{for(int i=0;i
{int mink=i,maxk=n-i-1;for(int j=i;j
{if(a[j]
}if(mink==n-i-1 && maxk==i) swap(a[i],a[n-i-1]);//避免二次交换
else if(maxk==i) swap(a[n-i-1],a[i]),swap(a[i],a[mink]);else swap(a[i],a[mink]),swap(a[maxk],a[n-i-1]);
}
}intmain()
{int a[8]={0,-1,-5,-7,-2,-4,-9,-3};
SelectionSort_TwoPoint(a,8);for(int i=0;i<8;i++)
printf("%d%c",a[i],i==7?'\n':' ');return 0;
}
四、选择排序-堆排序(Heap Sort)
什么是堆(Heap):
(1)堆中某个节点的值总是不大于或不小于其父节点的值;
(2)堆总是一颗完全二叉树(Complete Binary Tree)
完全二叉树是由满二叉树(Full Binary Tree)而引出来的。除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树称为满二叉树。
如果除最后一层外,每一层上的节点数均达到最大值;在最后一层上只缺少右边的若干结点,这样的二叉树被称为完全二叉树。
一棵完全二叉树,如果某个节点的值总是不小于其父节点的值,则根节点的关键字是所有节点关键字中最小的,称为小根堆(小顶堆);如果某个节点的值总是不大于其父节点的值,则根节点的关键字是所有节点关键字中最大的,称为大根堆(大顶堆)。
若一个数列满足
时可称之为堆(即任何一个子树的根节点所对应的元素一定是这颗子树所代表的所有元素中最小或最大的元素)
堆排序的核心是建树,任何一个树的父节点的个数为n/2,设父节点的标号为u,则左儿子的标号为2*u,右儿子的标号为2*u+1;
建树的核心为从父节点所在的最底层开始建树,每次比较父节点,左儿子和右儿子的元素大小,把最大最小的元素放到父节点的位置上(左儿子和右儿子的相对大小不做要求),若父节点的元素已经为最大(或最小),则继续向上建树,否则,交换元素后向下回溯。(建树从下往上,回溯从上往下)
以0,-1,-5,-7,-2,-4,-9,-3为例:
元素的个数为8,所以有4个父节点。
建树完成后,1节点为最大值,交换到数组最后,之后维护前面的数,调整二叉树,直到排序完成。
代码实现:
#include
using namespacestd;void HeapAdjust(int *a,int u,intn)
{int lson=2*u,rson=2*u+1,maxelement=u;if(u<=n/2)
{if(lson<=n && a[maxelement]