比較排序算法的Java實現

在我們熟知的排序算法中,最早接觸的就是冒泡排序和選擇排序,後來又有了插入排序,但是這些排序算法都是二次時間的,對於大量數據的排序效率不是很高。因此後面就有了如希爾排序,歸併排序,堆排序和快速排序。這裏總共有7種,因爲它們在排序時都會進行比較,因此也是比較排序算法,而比較排序的最快時間也要Ω(NlogN)。這時根據比較的決策樹得到。N個元素,它的排序有N!種情況,將它放入到二叉樹中,N!情況都在樹葉上,而具有N!的樹葉的二叉數的深度至少爲log(N!)=Ω(NlogN)。

     當然,如果不是比較排序,就可以突破這種現狀。線性排序算法我在另一篇文章中已經寫到,見 線性排序的Java實現

下面的圖是網上對於常見排序算法的總結:

1.插入排序Java代碼如下:

//插入排序 希爾排序是它的變形
public static void insertSort(int[] a)
{
	for(int i=0;i<a.length-1;i++)
	{
		int j=i+1;
		int tmp=a[j];
		for(;j>0 && tmp<a[j-1];j--)
			a[j]=a[j-1];
		a[j]=tmp;
	}
}


2.選擇排序

//選擇排序 不穩定排序
public static void chooseSort(int[] a)
{
	for(int i=0;i<a.length-1;i++)
	{
		int min=i;
		for(int j=i+1;j<a.length;j++)
		{
			if(a[j]<a[min])
				min=j;
		}
		int tmp=a[i];
		a[i]=a[min];
		a[min]=tmp;
	}
}


3.冒泡排序,進行改進可以達到最快時間O(N)

//冒泡排序  基本版
public static void bubbleSort(int[] a)
{
	for(int i=0;i<a.length;i++)
	{
		for(int j=1;j<a.length-i;j++)
		{
			if(a[j-1]>a[j])
			{
				int tmp=a[j-1];
				a[j-1]=a[j];
				a[j]=tmp;
			}
		}
	}
}
//冒泡排序改進 最優時間複雜度O(N)
public static void bubbleSortN(int[] a)
{
	boolean doswap;
	for(int i=0;i<a.length;i++)
	{
                doswap=false;
		for(int j=1;j<a.length-i;j++)
		{
			if(a[j-1]>a[j])
			{
				int tmp=a[j-1];
				a[j-1]=a[j];
				a[j]=tmp;
				doswap=true;
			}
		}
		if(doswap==false) //說明沒有交換,數組是順序的
			break;
	}
}


4.希爾排序,它是插入排序的變形,可以選取不同的增量

//希爾排序,就是插入排序的一種變形
public static void shellsort(int[] a){
	for(int gap=a.length/2;gap>0;gap=gap/2){
		for(int i=gap;i<a.length;i++){
			int tmp=a[i];
			int j=i;
			for(;j>=gap && tmp<a[j-gap];j=j-gap)
				a[j]=a[j-gap];
			a[j]=tmp;
		}
	}
}


5.堆排序  這裏需要有建堆,維護堆,堆排序

//維護堆
public static void maxHeapify(int[] a,int i,int size)
{
	int tmp=a[i];
	int child=i*2;
	while(child<=size)
	{
		if(child+1<size && a[child+1]<a[child])
			child++;
		if(a[child]<tmp)
			a[child/2]=a[child];
		else
			break;
		child=2*child;
	}
	a[child/2]=tmp;
}
//建堆  時間複雜度O(N)
public static void buildHeap(int[] a)
{
	for(int i=(a.length-1)/2;i>0;i--)  //只要對堆前一半的元素進行維護
	{
		maxHeapify(a,i,a.length-1);
	}
}
//堆排序算法  這是最小堆  輸出的數組是從大到小 且a[0]不算堆元素
public static void heapSort(int[] a)
{
	int temp;
	buildHeap(a);
	int size=a.length-1;  //去掉a[0]
	for(int i=size;i>1;i--)
	{
		temp=a[i];
		a[i]=a[1];
		a[1]=temp;
		size--;
		 maxHeapify(a,1,size);
	}
}


6.歸併排序

//歸併排序 遞歸方法  O(N)的空間複雜度
public static void mergeSort(int[] a){
	int[] tmp=new int[a.length];
	mergeSort(a,tmp,0,a.length-1);
}
private static void mergeSort(int[] a,int[] tmp,int left,int right){
	if(left<right)
	{
		int center=(left+right)/2;
		mergeSort(a,tmp,left,center);   //先分割,再合併處理;和快速排序是反的(快排:先處理,再分割)
		mergeSort(a,tmp,center+1,right);
		merge(a,tmp,left,center,right);
	}
}
private static void merge(int[] a,int[] tmp,int left,int center,int right){
	int num=right-left+1;
	int i=left;
	int j=center+1;
	int pos=left;
	while(i<=center&&j<=right)
	{
		if(a[i]<a[j])
			tmp[pos++]=a[i++];
		else
			tmp[pos++]=a[j++];
	}
	while(i<=center)
	{
		tmp[pos++]=a[i++];
	}
	while(j<=right)
	{
		tmp[pos++]=a[j++];
	}
	for(int q=left;q<=right;q++)
	{
		a[q]=tmp[q];
	}
}
//合併過程 O(1)空間複雜度,不建立臨時數組空間,但是時間代價會變大
private static void merge(int[] a,int left,int center,int right){
	int lpos=left;
	int rpos=center+1;   
	while(lpos<=center && rpos<=right)  //類似插入過程
	{
		if(a[lpos]<=a[rpos])
			lpos++;
		else
		{
			int tmp=a[rpos];
			for(int i=rpos;i>=lpos;i--)
			{
				a[i]=a[i-1];
			}
			a[lpos]=tmp;
			rpos++;
			lpos++;
		}
	}
}


7.快速排序

//快速排序
public static void quickSort(int[] a)
{
	quickSort(a,0,a.length-1);
}
private static void quickSort(int[] a,int left,int right)
{
	if(left<right)
	{
		int pivot=a[left];
		int i=left;
		int j=right;
		while(i<j)
		{
			while(a[j]>pivot && i<j){j--;}
			if(i<j)
				a[i++]=a[j];
			while(a[i]<pivot && i<j){i++;}
			if(i<j)
				a[j--]=a[i];
			
		}	
		a[i]=pivot;
		quickSort(a,left,i-1);
		quickSort(a,i+1,right);
         }
}

非遞歸實現,使用棧存儲

//快速排序的非遞歸實現,利用系統的棧stack
public class QuickSortNonRecursion {
	 public static void main(String[] args) {
	 	 QuickSortNonRecursion qsnr = new QuickSortNonRecursion(); 
	 	 int[] array = {0, 2, 11, 121, 18, 99, 3, 5, 101, 22, 9, 100}; 
	 	 qsnr.quicksort(array); for (int i : array) {
	 	 	 System.out.print(i + " "); } 
	 } 
	 public void quicksort(int[] array) { 
		if (array == null || array.length == 1) return; 
		//存放開始與結束索引 Stack<Integer> s = new Stack<Integer>(); 
		//壓棧 
		s.push(0); 
		s.push(array.length - 1); 
		//利用循環裏實現
		 while (!s.empty()) {
		 	 int right = s.pop(); 
		 	 int left = s.pop();
		 	  //如果最大索引小於等於左邊索引,說明結束了
		 	   if (right <= left) continue; 
		 	   int i = partition(array, left, right);
		 	    if (left < i - 1) {
		 	    	 s.push(left); s.push(i - 1);
		 	    } 
		 	    if (i + 1 < right) {
		 	    	 s.push(i+1); s.push(right);
		 	    	  }
		 	     }
		 	 }

 	  //找到軸心,進行交換 
		public int partition (int[] data, int first, int end) {
		 	  	 int temp; 
		 	  	 int i=first,j=end; 
		 	  	 if(first<end) { 
		 	  	 	temp=data[i]; 
		 	  	 	//當i=j的時候,則說明掃描完成了
		 	  	 	 while(i<j) { 
		 	  	 	 	//從右邊向左邊掃描找到一個小於temp的元素 
		 	  	 	 	while(j>i&&data[j]>temp)j--; if(i<j) {
		 	  	 	 		 //將該元素賦值給temp
		 	  	 	 		  data[i]=data[j]; 
		 	  	 	 		  //賦值後就應該將i+1指向下一個序號 
		 	  	 	 		  i++; } 
		 	  	 	 		  //然後從左邊向右邊開始掃描,找到一個大於temp的元素 
		 	  	 	 		  while(i<j&&temp>data[i])i++; 
		 	  	 	 		  if(i<j) { 
		 	  	 	 		  	//將該元素賦值給temp
		 	  	 	 		  	 data[j]=data[i]; 
		 	  	 	 		  	 //賦值後就應該將j-1指向前一個序號 
		 	  	 	 		  	 j--; 
		 	  	 	 		  	 }
		 	  	 	 		  } //將軸數據放在i位置中 
		 	  	 	 	data[i]=temp;
		 	  	 	 	}
		 	  	 	  return i;
		 	  	 	 	 } 
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章