一、冒泡排序
//基本算法 for(i=1;i<list.length;k++){ //perform the kth pass for(j=0;list.length-i;j++){ if(list[j]<list[j+1]){ swap list[j] with list[j]; } } } //改进算法 //如果在某次遍历时没有发生交换,那么就不用进行下一次遍历 for(i=1;i<list.length;k++){ needNextPass=false; for(j=0;j<list.length-i;j++){ if(list[j]<list[j+1]){ swap list[j] with list[j]; needNextPass=true;//need next pass } } }
对于改进算法的排序时间,最佳情况:O(n);最坏情况:O(n2)
二、归并排序
(1)算法描述:将数组分为两半,对每部分递归地应用归并排序。在两部分都排好序后,对他们进行归并。
public static void mergeSort(int[] list){ if(list.lenght>1){ mergeSort(list[0~list.length/2]); mergeSort(list[list.length/2+1~list.length-1]); merge list[0~list.length/2] with list[list.length/2+1~list.length-1]; } }
(2)算法实现:
public class MergeSort{ public static void mergeSort(int[] list){ if(list.length>1){ int[] firstHalf=new int[list.length/2]; System.arraycopy(list,0,firstHalf,0,list.length/2); mergeSort(firstHalf); int[] secondHalf=new int[list.length-list.length/2]; System.arraycopy(list,list.length/2,secondHalf,0,secondHalf.length); mergeSort(secondHalf); int[] temp=merge(firstHalf,secondHalf); System.arraycopy(temp,0,list,0,temp.length); } } private static int[] merge(int[] list1,int[] list2){ int[] temp=new int[list1.length+list2.length]; int current1=0,current2=0,current3=0; while(current1<list1.length&¤t2<list2.length){ if(list1[current1]<list2[current2]) temp[current3++]=list1[current1++]; else temp[current3++]=list2[current2++]; } while(current1<list1.length){ temp[current3++]=list1[current1++]; } while(current2<list2.length){ temp[current3++]=list2[current2++]; } return temp; } public static void main(String[] args){ int[] list={2,3,2,5,6,1,-1,3,14,12}; mergeSort(list); for(int e:list) System.out.print(e+" "); } }
(3)总结:归并排序时间O(nlogn)。该算法优于选择排序,插入排序和冒泡排序。java.util.Arrays类中的sort方法是使用归并排序算法的变体实现的。
三、快速排序
(1)算法描述:在数组中选择一个称为主元(pivot)的元素,将数组分为两部分使得第一部分中的所有元素都小于或等于主元,而第二部分都大于或等于主元。依次对两部分递归地应用快速排序算法。
public static void quicksort(int[] list){ if(list.length>1){ select a pivot; patition list into list1 an list2 such that all elements in list1 <= pivot and all elements in list2 > pivot quicksort(list1); quicksort(list2); } }
(2)算法实现:
package Algorithm; public class QuickSort{ public static void quicksort(int[] list){ quicksort(list,0,list.length-1); } public static void quicksort(int[] list,int left,int right){ if(right>left){ int temp=list[left]; int i=left; int j=right; while(i!=j){ //顺序很重要,要先从右边开始找 while(list[j]>=temp && i<j){ j--; } //再找左边的 while(list[i]<=temp && i<j){ i++; } //交换两个数在数组中的位置 if(i<j){ int t=list[i]; list[i]=list[j]; list[j]=t; } } //最终将基准数归位 list[left]=list[i]; list[i]=temp; quicksort(list,left,i-1); quicksort(list,i+1,right); } } public static void main(String[] args) { int[] list={6,5,3,8,4,9,7}; quicksort(list); for(int u:list) System.out.print(u+","); } }
(3)总结:在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实作出来。
四、堆排序
(1)堆的定义:n个元素序列{k1,k2,...,kn}当且仅当满足以下关系时,称之为堆。
ki<=k2i且ki<=k2i+1 (小根堆) 或 ki>=k2i且ki>=k2i+1 (大根堆)。
可将其对应为完全二叉树。堆顶元素为n个数中的最小/大值。若在输出堆顶的最小/大值之后,使得剩余n-1个元素又建成一个堆,则得到n个元素中的次小/大值。依次类推,便可得到一个有序序列,这个过程称为堆排序。
(2)算法描述:
由堆排序的定义可知,该算法的关键在于建堆和删除堆顶元素后的调整。
//建堆
Let the last node be current node;
while(the current node > its parent){
Swap current node with its parent;
}
//删除堆顶元素后的调整
Move the last node to replace the root;
Let the root be the current node;
(3)算法实现
//Heap类
class Heap<E extends Comparable>{
private java.util.ArrayList<E> list=new java.util.ArrayList<E>();
public Heap(){
}
public Heap(E[] objects){
for(int i=0;i<objects.length;i++){
add(objects[i]);
}
}
//建堆
public void add(E newObject){
list.add(newObject);
int currentIndex=list.size()-1;
while(currentIndex>1){
int parrentIndex=(currentIndex-1)/2;
if(list.get(currentIndex).compareTo(list.get(parrentIndex))>0){
E temp=list.get(currentIndex);
list.set(currentIndex,list.get(parrentIndex));
list.set(parrentIndex,temp);
}
else
break;
currentIndex=parrentIndex;
}
}
//删除堆顶元素后的调整
public E remove(){
if(list.size()==0)
return null;
E removedObject=list.get(0);
list.set(0,list.get(list.size()-1));
list.remove(list.size()-1);
int currentIndex=0;
while(currentIndex<list.size()){
int leftChildIndex=2*currentIndex+1;
int rightChildIndex=2*currentIndex+2;
//找出左右子树中较大的
if(leftChildIndex>=list.size()) break;//已经是堆了
int maxIndex=leftChildIndex;
if(rightChildIndex<list.size()){//若有又子树
if(list.get(maxIndex).compareTo(list.get(rightChildIndex))<0){
maxIndex=rightChildIndex;
}
}
//比较目前节点与左右子树中的最大值,若目前节点小,则交换
if(list.get(currentIndex).compareTo(list.get(maxIndex))<0){
E temp=list.get(currentIndex);
list.set(currentIndex,list.get(maxIndex));
list.set(maxIndex,temp);
currentIndex=maxIndex;
}
else
break;
}
return removedObject;
}
public int getSize(){
return list.size();
}
}
//使用Heap类进行排序
public class HeapSort{
public static <E extends Comparable> void heapSort(E[] list){
Heap<E> heap=new Heap<E>();
for(int i=0;i<list.length;i++){
heap.add(list[i]);
}
for(int i=list.length-1;i>=0;i--){
list[i]= heap.remove();
}
}
public static void main(String[] args){
Integer[] list={5,4,3,2,1};
heapSort(list);
for (Integer u:list)
System.out.print(u+",");
}
}
(4)总结:和归并排序一样,时间都为O(nlogn)。为了归并两个子数组,归并需要一个临时数组,而堆排序不需要临时的数组空间,因此,堆排序的空间效率高于归并排序。