插入排序
- 取第一个元素array[0],放置在最前面,可不操作,自动满足;
- 取array[1],与array[0]比较,若小于,则将array[0]后移移位,将array[1]放在arrat[0]处;
- 再次循环:去array[2],依次向前,与array[1]比较,若小于,则将array[1]后移移位,,再与array[0]比较,依次类推,直到某个array[j-1]<array[2],则将array[2]放在array[j]的位置.
- 计算复杂度:平均比较次数(1+2+3+4+...+n-1)/2; 平均移动次数:(1+2+3+4+...+n-1)/2;如果输入数据已经事先排序,那么下方内层循环总是立即终止,那么插入排序将运行很快。O(n^2)
代码实现:
public void insert(AnyType[] array){
//第j次迭代,将前j+1个元素,按序排在前j+1个位置上
int j;
for (int i = 1; i < array.length; i++) {
//记录元素array[j],这是将被排序的元素
AnyType tmp=array[j];
//从小达到排序,若该元素A小于已经排好某个元素array[j-1],则退出循环,将A放在array[j]的位置处
for (int j = i; tmp.compareTo(array[j-1])<0; j--) {
//将大于A的元素向后移动一位
array[j]=array[j-1];
}
array[j]=tmp;
}
}
选择排序法
- 两层循环:第一次选择最小的元素,放在第一位
- 第二次选择次小的元素,放在第二位。。依次类推
- 不依赖与输入数据的初始状态,排序性能稳定 O(n^2)
代码实现:
public void select(AnyType[] array){
for (int i = 0; i < array.length; i++) {
AnyType tmp=array[i];
int index;
//寻找j-array.length-1的所有元素中最小的
for (int j = i+1; j < array.length; j++) {
if( tmp.compareTo(array[j])>0 )
index=j;
}
array[i]=array[index];
array[index]=tmp;
}
}
希尔排序
希尔排序也叫缩减增量排序。依次减小增量,直到1,并行排序的始祖。希尔排序依赖与增量序列的选择
运算复杂度:最差情况为O(n^2)
代码实现:
下面代码中增量序列的选择为(
array.length/2、
array.length/2^2、array.length/2^3 ... 1
)
public void shell(AnyType[] array){
//依次减小增量,直到1
for (int gap = array.length/2; gap>0 ; gap/=2) {
int j;//将J定义到外面,只创建依次,内层循环可多次重复使用,减少虚拟机运行开销
for (int i = gap; i < array.length; i++) {
AnyType tmp=array[i];
//从后往前比较,前面都是已经排好序的,可以迅速找到第一个不符合要求的,即找到新元素array[i]的适当位置,
// array[j]限制j的合法位置,array[j].compartTo(array[j-gap])<0为判断不成立条件,立即终止循环
for (j = i; j>gap && tmp.compartTo(array[j-gap])<0; j-=gap) {
array[j]=array[j-gap];
}
//循环终止后,将tmp放在合适的位置,这里的
array[j]=tmp;
}
}
}
堆排序
优先队列可以用
O(NlogN)
时间排序,基于堆排序的思想。,
思路:建立N个元素的二叉堆的基本策略,花费时间O(N),最坏情况为O(NlogN),然后执行N次deleteMin操作,每个操作花费O(logN)时间,故总共时间为:
O(NlogN)。将
每次删除的元素存储在一个新数组中,这样,删除结束后,需要将排好序的新数组中序列重新复制到原始优先队列的数组内存中。要求两倍的存储空间。
改进方法:如要求从小到大排序:可首先将序列排在一个最大堆中,这样每次删除的堆顶为最大元素,然后将其存储在优先队列的尾部。例如:堆有6个元素,首先删除a1,现在堆有5个元素,可以把a1放在位置6处,再删除a2,现在堆有4个元素,把a2放在位置5处,依次类推,最后依次delete操作后,数组将以递减的顺序包含这些元素。
代码实现:
//数组从0开始存数元素,计算n的左子树位置
public static int leftChild(int n){
return 2*n+1;
}
//将优先队列中的元素变成最大堆
private static <AnyType extends Comparable<?super AnyType>> void perDown(AnyType[] array,int i,int n){
int child;
AnyType tmp;
//采用下滤法,生成包含n个元素的最大堆
for (tmp = array[i]; leftChild[i]<n; i=child) {
child = leftChild(i);
if(child!=n-1&& array[child].compareTo(array[child+1])<0)
child++;//child始终存储子节点中较大的那个
if(tmp.compareTo(array[child])<0){
array[i]=array[child];
}else
break;
}
array[i]=tmp;
}
//标准的堆排序算法
public static <AnyType extends Comparable<? super AnyType>> void heapSort(AnyType[] array){
//buildHeap
for (int i = array.length/2; i >=0; i--) {
perDown(array,i,array.length);
}
//deleteMax
for (int i = array.length; i>0; i--) {
//将最大值放在数组尾部合适的位置
swapReference(array,0,i);
perDown(array,0,i);
}
}
快速排序法:
递归调用归并排序的思想 O(NlogN)
- 若S中的元素个数为0或1,则返回
- 取S中任一元素v,称之为枢纽元
- 将S-{v}划分我两个不相交的集合,S1中的元素小于v,S2中的元素大于v,
- 返回quickSort(S1),后跟v,再跟quickSort(S2)。
重点在于枢纽元的选取,尽量是S1和S2分布均匀,通常做法是:
三数中值分割法
代码实现:
//快速排序法
//三值中值分割法
, [left]<=[mid]<=[right]
public <AnyType extends CompareTo<?super AnyType>> AnyType median(Anytype[] array,int left,int right){
int mid;
if(left+1<right){
mid=left+(right-left)/2;
//二者中较小的值
AnyType tmp1=array[left].compareTo(array[mid])<0 ? array[left]:array[mid];
//二者中较大的值
AnyType tmp2=array[left].compareTo(array[mid])>0 ? array[left]:array[mid];
AnyType biggest;
AnyType smaller;
if(tmp2.compareTo(array[right])>0){
biggest=tmp2;
smaller=array[right];
}else{
biggest=array[right];
smaller=tmp2;
}
array[left]=smaller.compareTo(tmp1)<0 ? smaller:tmp1;
array[mid]=smaller.compareTo(tmp1)>0 ? smaller:tmp1;
array[right]=biggest;
}
return array[mid];
}
//awapReference
public void swapReference(AnyType array , int i,int j){
AnyType tmp=array[i];
array[i=array[j];
array[j]=tmp;
}
//快速排序法主例程
public static <AnyType extends CompareTo<?super AnyType>> void quickSort(AnyType[] array,int left,int right){
//若元素个数太少,则用插入排序法更快
int cutoff=10;
if(left+cutoff<right){
AnyType pivot =median(array,left,right);
int i=left,j=right;
for(;;){
//注意,这里使用了++i/--j,因此,必须保证上述median中,[left]<=[mid]<=[right]
while(array[++i].compareTo(pivot)<0){}
while(array[--j].compareTo(pivot)>0){}
if(i<j){
swapReference(array,i,j);
}else
break;
}
quickSort(array,left,i-1);
quickSort(array,i+1,right);
}else{
insert(array,left,right);
}
}