Java 堆排序算法 和 快速排序算法的效率比較

堆排序算法 與 快速排序算法 的運行效率比較

堆排序算法:
堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似徹底二叉樹的結構,並同時知足堆積的性質:即子結點的鍵值或索引老是小於(或者大於)它的父節點。html

堆排序的平均時間複雜度爲Ο(nlogn) 。web

算法步驟:算法

建立一個堆H[0…n-1]數組

把堆首(最大值)和堆尾互換數據結構

  1. 把堆的尺寸縮小1,並調用shift_down(0),目的是把新的數組頂端數據調整到相應位置架構

  2. 重複步驟2,直到堆的尺寸爲1
    在這裏插入圖片描述
    以上截至(https://www.runoob.com/w3cnote/the-friendship-algorithm-the-big-bang-theory.html)ide

/**
 * 堆排序算法:
 * @author Administrator
 * @time 2019年7月12日 下午9:08:02
 * 
 * 堆排序的前提:升序(構造大根堆),降序(構造小根堆)
 * 
 * 具體思路: https://blog.csdn.net/u010452388/article/details/81283998
 */


public class HeapSort {
	
	//數組數值交換
	public void swap(int[] arr,int i,int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	
	//構造大根堆
	public void bigRootHeap(int[] arr) {
		
		for(int i=0;i<arr.length;i++) {
			//設置當前索引節點
			int currentIndex = i;
			int fatherIndex = (currentIndex-1)/2;
			
			while(arr[currentIndex] > arr[fatherIndex]) {
				swap(arr,currentIndex,fatherIndex);
				
				currentIndex = fatherIndex;
				fatherIndex = (currentIndex-1)/2;
			}		
		}
	}
	
	//固定最大值,再構造大根堆
	public void heapNext(int[] arr,int index,int size) {
		int left = 2*index+1;
		int right = 2*index+2;
		while (left < size) {
            int largestIndex;
            //判斷孩子中較大的值的索引
            if (arr[left] < arr[right] && right < size) {
                largestIndex = right;
            } else {
                largestIndex = left;
            }
            //比較父結點的值與孩子中較大的值,並肯定最大值的索引
            if (arr[index] > arr[largestIndex]) {
                largestIndex = index;
            }
            //若是父結點索引是最大值的索引,那已是大根堆了,則退出循環
            if (index == largestIndex) {
                break;
            }
            //父結點不是最大值,與孩子中較大的值交換
            swap(arr, largestIndex, index);
            //將索引指向孩子中較大的值的索引
            index = largestIndex;
            //從新計算交換以後的孩子的索引
            left = 2 * index + 1;
            right = 2 * index + 2;
        }

	}
	
	
	public void heapSort(int[] arr) {
		bigRootHeap(arr);
        int size = arr.length;
        while (size > 1) {
            //固定最大值
            swap(arr, 0, size - 1);
            size--;
            //構造大根堆
            heapNext(arr, 0, size);
 
        }

	}
	
	
	public static void main(String[] args) {
		
		int[] arr = new int[1000];
		
		for(int i=0;i<1000;i++) {
			if(i%2 == 0) {
				arr[i] = 2*i-i;
			}
			else {
				arr[i] = 2*i;
			}			
		}
		
		System.out.print("原數組:");
		for(int x:arr) {
			System.out.print(x+",");
		}
		
		HeapSort hs = new HeapSort();
		long start = System.nanoTime();
		hs.heapSort(arr);
		long end = System.nanoTime();
		System.out.println("\n堆排序消耗時間:"+(end-start));
		
		System.out.print("排序後數組:");
		for(int x:arr) {
			System.out.print(x+",");
		}
	}
}

在這裏插入圖片描述

快速排序算法:
快速排序是由東尼·霍爾所發展的一種排序算法。在平均情況下,排序 n 個項目要Ο(n log n)次比較。在最壞情況下則須要Ο(n2)次比較,但這種情況並不常見。事實上,快速排序一般明顯比其餘Ο(n log n) 算法更快,由於它的內部循環(inner loop)能夠在大部分的架構上頗有效率地被實現出來。svg

快速排序使用分治法(Divide and conquer)策略來把一個串行(list)分爲兩個子串行(sub-lists)。oop

算法步驟:ui

1 從數列中挑出一個元素,稱爲 「基準」(pivot),

2 從新排序數列,全部元素比基準值小的擺放在基準前面,全部元素比基準值大的擺在基準的後面(相同的數能夠到任一邊)。在這個分區退出以後,該基準就處於數列的中間位置。這個稱爲分區(partition)操做。

3 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。

遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,可是這個算法總會退出,由於在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。
在這裏插入圖片描述
(來自:https://www.runoob.com/w3cnote/the-friendship-algorithm-the-big-bang-theory.htm)

public class QuickSort {

	public static void quickSort(int[] arr,int left,int right) {
		//定義i,j而且將傳遞來的參數分別賦值給i,j
		int i = left;
		int j = right;
		
		//判斷:當數組最左邊的數的下標反而大於最右邊的數的下標時,則參數傳遞存在錯誤
		if(i > j) {
			return;
		}
		//設置基準數
		int temp = arr[left];
		//判斷:當數組下標左邊不等於右邊的時候,才能夠進行查找與替換
		while(i != j) {
			/*
			 * 1.先在基準數右邊進行查找比基準數小的數
			 * 2.找不到,便一直向數組的源頭逐步向上找
			 * 3.找到時,便中止繼續查找
			 */
			while(arr[j] >= temp && i < j) {
				j--;
			}
			/*
			 * 1.先在基準數左邊邊進行查找比基準數大的數
			 * 2.找不到,便一直向數組的末尾逐步向下找
			 * 3.找到時,便中止繼續查找
			 */
			while(arr[i] <= temp && i < j) {
				i++;
			}
			
			/*
			 * 當知足最左下標小於最右下標時,將剛剛在數組右端比基準數小的數
			 * 與在數組中左端比基準數大的數,進行相互替換,以達到排序的做用
			 */
			if(i < j) {
				int tp = arr[j];
				arr[j] = arr[i];
				arr[i] = tp;
			}
			
		}
		/*
		 * 現將i=j時,i所對應的數組中的數的賦值在原基準數的位置
		 * (本例中默認是數組的第一個位置)
		 * 將基準數放置在剛纔i=j的位置上
		 */
		arr[left] = arr[i];
		arr[i] = temp;
		
		//執行遞歸操做,分別對剛剛第一步排序的產生在基準書左邊與右邊的數組進行進一步的排序
		quickSort(arr,left,i-1);
		quickSort(arr,i+1,right);
	}

	public static void main(String[] args) {
		int[] arr = new int[1000];;
		
		/*系統本身產生一個足夠大的數組
		 * 由於System.nanoTime()是以毫微秒爲單位的時間計算
		 * 計算機運行速度很快,咱們須要產生一個足夠大的數組來排序,
		 * 從而來觀察不一樣算法之間效率的差別
		 */
		for(int i=0;i<1000;i++) {
			if(i%2 == 0) {
				arr[i] = 2*i-i;
			}
			else {
				arr[i] = 2*i;
			}			
		}

		//遍歷原數組
		System.out.print("原始數組:");
		for(int x:arr) {
			System.out.print(x+" ");
		}
		
		long start = System.nanoTime();
		quickSort(arr,0,arr.length-1);
		long end = System.nanoTime();
		
		//遍歷排序後數組
		System.out.print("\n快速排序後:");
		for(int x : arr) {
			System.out.print(x+" ");
		}
		
		System.out.println("\n快速排序算法消耗時間:"+(end-start));
	}
}

在這裏插入圖片描述

堆排序是一種選擇排序,複雜度通常認爲就是O(nlogn)級。