Java內部排序之插入排序與交換排序詳解
內部排序
排序:將任意序列重新排列按照關鍵字有序;
排序根基存儲器的不同分為:內部排序、外部排序;(這里指的都是內部排序)
排序根據關鍵字分為:穩(wěn)定排序、不穩(wěn)定排序
排序根據不同的原則分為:插入排序、交換排序、選擇排序、歸并排序、基數排序;
排序根據時間復雜度分為:簡單排序(O(N2))、先進排序(O(nlogn))、基數排序(O(d*n))
排序的操作:比較、移動 被稱為基于比較的排序;
假設這里使用的存儲結構均為:順序存儲結構;
內部排序:
1、插入排序:直接插入排序、折半插入、2-路插入排序、希爾排序
2、交換排序:冒泡排序、快速排序
3、選擇排序:簡單選擇排序、堆排序
4、歸并排序
5、基數排序
插入排序
1直接插入排序
由n-1趟排序組成; 對于P=1趟到P=N-1趟,插入排序保證從位置0到位置P上的元素為已排序狀態(tài);
第P趟,我們將位置P上的元素向左移動到它在前P+1個元素中正確位置上。(這里需要使用一個哨兵元素)
直接插入程序示例:
public class InserSort { public static void insertSort(int a[]){ int temp;//哨兵 int i;//執(zhí)行趟數 int j; for (i = 1; i < a.length; i++) {//執(zhí)行N-1趟 temp=a[i]; for ( j = i-1; (j >=0)&&(a[j]>temp); j--) { a[j+1]=a[j]; } a[j+1]=temp; } } public static void main(String[] args) { int a[]={9,6,3,2,7,5}; InserSort.insertSort(a); for (int i = 0; i < a.length; i++) { System.out.print(a[i]); } } }
算法分析:
排序的操作:比較、移動
1、空間復雜度: 只需要一個記錄的輔助空間;
2、時間復雜度:O(N2) 如果已有序時間復雜度為:O(N)
3、適應場景:數據量不是很大 、基本有序
2 折半插入排序
將查找工作交與“折半查找”來實現(xiàn)。定位后,后續(xù)移動元素。
public class BInsertSort { /** * 折半插入排序 * @param a */ public static void BinsertSort(int a[]){ int temp;//哨兵 for (int i = 1; i < a.length; i++) { temp=a[i]; int low=0; int hight=i-1; //查詢 while (low<=hight) { int mad=(low+hight)/2; if (a[mad]>a[i]) { hight=mad-1; } if (a[mad]<a[i]) { low=mad+1; } } //移動 for (int k = i-1; k >=hight+1; k--) { a[k+1]=a[k]; } a[hight+1]=temp; } } public static void main(String[] args) { int a[]={9,6,3,2,7,5}; BInsertSort.BinsertSort(a); for (int i = 0; i < a.length; i++) { System.out.print(a[i]); } } }
折半插入排序減少關鍵字的比較次數,但是記錄的移動次數沒有改變。
時間復雜度:O(N2)
3 希爾排序(縮小增量排序)
基本思想:先將整個待排序記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄“基本有序”時,在對整個記錄進行一次直接插入排序。
希爾排序使用一個序列,叫做增量序列。
序列最終值為1 PS:增量序列中的值沒有除1之外的公因子,并且最后一個增量必須等于1;
算法示例: 增量序列最流行的選擇是使用shell建議的序列N/2
public class ShellSort { /** * 希爾排序 * @param a */ public static void shellSort(int a[]){ int i,j; int inc;//增量 int temp;//哨兵 for ( inc = a.length/2; inc >0; inc/=2) {//設置增量隊列 //一趟希爾排序 for ( i = inc; i < a.length; i++) { temp=a[i]; for ( j = i; j >= inc; j-=inc) { if (temp<a[j-inc]) { a[j]=a[j-inc]; }else { break; } } a[j]=temp; } } } public static void main(String[] args) { int a[]={9,6,3,2,7,5}; shellSort(a); for (int i = 0; i < a.length; i++) { System.out.print(a[i]); } } }
算法分析: 希爾排序的運算時間依賴于增量序列的選擇,最壞情況O(N2)
使用場景: 適度地大量的輸入數據
交換排序
交換排序:冒泡排序、快速排序
1 冒泡排序
思路: 一趟排序:將第一個記錄的關鍵字與第二個關鍵字進行比較,若為逆序記錄交換,然后比較第二個與第三個,以此類推,直到地N-1個記錄與N個記錄比較位置。
其結果使得最大的記錄安置在最后一個記錄位置; 第二趟對n-1個記錄進行冒泡排序。
判斷冒泡排序結束的條件:在一趟排序中沒有進行過交換記錄的操作。 算法演示:
public class BubbleSort { /** * 冒泡排序 * @param a */ public static void bubbleSort(int a[]){ int temp=0; int log=0;//1表示有交換 0表示沒有交換 作為結束標識 for (int i = a.length-1; i >1; i--) { for (int j = 0; j < i; j++) { if (a[j+1]<a[j]) { temp=a[j+1]; a[j+1]=a[j]; a[j]=temp; log=1; } } if (log==0) { break; } } } public static void main(String[] args) { int a[]={2,3,5,6,7,9}; BubbleSort.bubbleSort(a); for (int i = 0; i < a.length; i++) { System.out.print(a[i]); } } }
算法分析: 時間復雜度:O(N2)
2快速排序
快速排序(Quick Sort)的基本思想:通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續(xù)進行排序,以達到整個序列有序。
首先選擇一個記錄(可選擇第一個記錄,不是最佳的做法)作為支點(pivot),然后按下述原則重新排列其余記錄:將所有關鍵字較它小的記錄都安置在它的位置之前,將所有關鍵字較它大的記錄都安置在它位置之后。
由此可以該支點記錄最后所落的位置i作為分界線,這就是一趟快速排序。 具體做法:附設兩個指針low和high,它們的初值分別指向序列的前端與后端,設支點的記錄關鍵字為pivotkey,則首先從high所指位置起向前搜索找到第一個關鍵字小于pivotkey的記錄和支點記錄交換,然后從low所指位置起向后搜索,找到第一個關鍵字大于pivotkey的記錄和支點記錄相互交換,重復這兩步直到low=high為止。
算法示例:
public class QuickSort { /** * 一趟快排序 */ public static int partition(int a[],int low ,int high) { int temp = a[low];// 支點 while (low < high) { while ((low < high)&&(a[high] >= temp) ) { high--; } a[low]=a[high]; while ((low < high)&&(a[low] <= temp)) { low++; } a[high]=a[low]; } a[low]=temp; return low; } /** * 遞歸排序 * @param a * @param low * @param high */ public static void QSort(int a[],int low,int high){ //對子序列進行排序 if (low<high) { int pivot=partition(a, low , high); QSort(a,low, pivot-1); QSort(a,pivot+1,high); } } /** * 快速排序 * @param a */ public static void QuickSort(int a[]){ QSort(a, 0, a.length-1); } //測試 public static void main(String[] args) { int a[]={7,6,3,8,4,9,7}; QuickSort.QuickSort(a); for (int i = 0; i < a.length; i++) { System.out.print(a[i]); } } }
算法分析:
1、時間復雜度: 快速排序的平均時間為:O(nlogn) 就平均時間而言,快排序是目前被認為最好的一種內部排序方法; 較壞的情況:當關鍵字基本有序或者有序時,快速排序將托變?yōu)槊芭菖判?,時間復雜度:O(n2); 支點的選取可以優(yōu)化該算法,一般認為“三者取中”的做法最合適:即a[i],a[j],a[(i+j)/2],取三者的中值。這樣可以改善最壞情況下的性能。
2、空間復雜度: 平均空間復雜度為:O(log2N) 因為快速排序需要一個棧空間來實現(xiàn)遞歸。 一般如果一趟排序記錄均勻分布在支點兩側,棧的深度為log2N+1 最壞情況,一趟排序后,都跑到一端空間,深度為N 降低空間復雜度的方法: 在一趟排序之后比較分割所得兩部分的長度,且先對長度短的子序列中的記錄進行快速排序,則棧的最大深度可降為O(logn).
到此這篇關于Java內部排序之插入排序與交換排序詳解的文章就介紹到這了,更多相關Java插入排序與交換排序內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
FastDFS分布式文件系統(tǒng)環(huán)境搭建及安裝過程解析
這篇文章主要介紹了FastDFS分布式文件系統(tǒng)環(huán)境搭建及安裝過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-08-08使用Spring AOP實現(xiàn)MySQL數據庫讀寫分離案例分析(附demo)
分布式環(huán)境下數據庫的讀寫分離策略是解決數據庫讀寫性能瓶頸的一個關鍵解決方案,這篇文章主要介紹了使用Spring AOP實現(xiàn)MySQL數據庫讀寫分離案例分析(附demo),有興趣的可以了解一下。2017-01-01