Java數(shù)據(jù)結(jié)構(gòu)之選擇排序算法的實現(xiàn)與優(yōu)化
初識選擇排序
算法思想[以升序為例]:
第一趟選擇排序時,從第一個記錄開始,通過n-1次關(guān)鍵字的比較,從第n個記錄中選出關(guān)鍵字最小的記錄,并和第一個記錄進行交換
第二趟選擇排序時,從第二個記錄開始,通過n-2次關(guān)鍵字的比較,從第n-1個記錄中選出關(guān)鍵字最小的記錄,并和第二個記錄進行交換
…
第i趟選擇排序時,從第i個記錄開始,通過n-i次關(guān)鍵字的比較,從n-i+1個記錄中選擇出關(guān)鍵字最小的記錄,并和第i個記錄進行交換
反復進行上述步驟,經(jīng)過n-1趟選擇排序,將把n-1個記錄排到位,最后剩下的那個元素同樣已經(jīng)就位,所以共需進行n-1趟選擇排序
文字描述[以升序為例]
將數(shù)組分為兩個子集,排序的和未排序的,每一輪從未排序的子集中選出最小的元素,放入排序子集,重復上述步驟,直至整個數(shù)組有序
算法實現(xiàn)
代碼如下:
package bin_find; import java.util.Arrays; public class selectionSort { public static void main(String[] args) { int[] a={5,3,7,2,1,9,8,4}; selection(a); } private static void selection(int[] a){ for(int i=0;i<a.length-1;i++) {//n個元素參與排序,需要進行n-1次 for (int j = i + 1; j < a.length; j++) {//每輪i+1---a.length個元素之間相比較 if (a[i] > a[j]) {//前者大于后者,則進行交換 swap(a, i, j); } } System.out.println("第"+(i+1)+"輪選擇排序的結(jié)果"+Arrays.toString(a)); } } public static void swap(int arr[],int i,int j){ int t=arr[i]; arr[i]=arr[j]; arr[j]=t; } }
輸出如下:
第1輪選擇排序的結(jié)果[1, 5, 7, 3, 2, 9, 8, 4]
第2輪選擇排序的結(jié)果[1, 2, 7, 5, 3, 9, 8, 4]
第3輪選擇排序的結(jié)果[1, 2, 3, 7, 5, 9, 8, 4]
第4輪選擇排序的結(jié)果[1, 2, 3, 4, 7, 9, 8, 5]
第5輪選擇排序的結(jié)果[1, 2, 3, 4, 5, 9, 8, 7]
第6輪選擇排序的結(jié)果[1, 2, 3, 4, 5, 7, 9, 8]
第7輪選擇排序的結(jié)果[1, 2, 3, 4, 5, 7, 8, 9]
優(yōu)化后的算法實現(xiàn)
優(yōu)化思路
減少交換次數(shù),每一輪可以先找到最小的索引,再每輪最后再交換元素
代碼如下:
package bin_find; import java.util.Arrays; public class selectionSort { public static void main(String[] args) { int[] a={5,3,7,2,1,9,8,4}; selection(a); } private static void selection(int[] a){ //代表每輪選擇最小元素要交換到的目標索引 for(int i=0;i<a.length-1;i++) { int s = i;//代表最小元素的索引[這里是升序]---第一次最小元素的索引為1,第二次最小元素的索引為2..... //從當前最小元素的下一位元素開始直到最后一個元素---完成一次選擇排序 for (int j = s + 1; j < a.length; j++) { //[這里是升序],前者大于后者,則將更小數(shù)的索引值賦值給s,因為變量s本身代表的含義為最小元素的索引 if (a[s] > a[j]) { s = j; } } if (s != i) {//若不是同一個數(shù),則進行交換 swap(a, s, i); } System.out.println("第"+(i+1)+"輪選擇排序的結(jié)果"+Arrays.toString(a)); } } public static void swap(int arr[],int i,int j){ int t=arr[i]; arr[i]=arr[j]; arr[j]=t; } }
輸出:
第1輪選擇排序的結(jié)果[1, 3, 7, 2, 5, 9, 8, 4]
第2輪選擇排序的結(jié)果[1, 2, 7, 3, 5, 9, 8, 4]
第3輪選擇排序的結(jié)果[1, 2, 3, 7, 5, 9, 8, 4]
第4輪選擇排序的結(jié)果[1, 2, 3, 4, 5, 9, 8, 7]
第5輪選擇排序的結(jié)果[1, 2, 3, 4, 5, 9, 8, 7]
第6輪選擇排序的結(jié)果[1, 2, 3, 4, 5, 7, 8, 9]
第7輪選擇排序的結(jié)果[1, 2, 3, 4, 5, 7, 8, 9]
未進行優(yōu)化的算法輸出:
進行優(yōu)化的算法輸出:
通過比較二者的輸出結(jié)果,我們能夠很明顯的感覺到,經(jīng)過優(yōu)化后的算法在實現(xiàn)的過程中,數(shù)據(jù)之間的交換次數(shù)明顯減少
選擇排序 VS 冒泡排序
1:二者的平均復雜度都是O(n^2),但是當有序數(shù)組使用冒泡排序時,其時間復雜度為O(n)
2:選擇排序一般要快于冒泡排序,因為其交換的次數(shù)少
3:但如果集合有序度高,那么冒泡排序優(yōu)先于選擇排序
例:在上篇文章的冒泡排序優(yōu)化算法中,我們通過設(shè)置變量,去判斷當前的數(shù)組元素是否發(fā)生交換,如果未發(fā)生交換,則證明當前數(shù)組已經(jīng)有序,不再進行排序
4:冒泡排序?qū)儆诜€(wěn)定排序算法,而選擇屬于不穩(wěn)定排序
穩(wěn)定 VS 不穩(wěn)定:即為兩個大小相等的數(shù),在參與排序之前具有先后關(guān)系,若排序完成,這兩個數(shù)的先后順序并未發(fā)生改變,那么即為穩(wěn)定排序,否則為不穩(wěn)定排序
舉例:
(3,3,2)
對于上述數(shù)組:
參與冒泡排序:
第一輪:3和3相等,無需交換位置,3和2交換位置
第二輪:3和2交換位置
排序結(jié)束,排序后的結(jié)果為(2,3,3)
參與選擇排序:
第一輪:將3取出,與3比較,3不滿足大于3,再與2進行比較,滿足大于2,交換位置
第二輪:將3取出,與3進行比較,不滿足大于3
排序結(jié)束,排序成功,排序后的結(jié)果為(2,3,3)
通過兩種方法的排序結(jié)果,我們不難看出通過冒泡排序算法,兩個大小相等的數(shù)的先后關(guān)系并沒有發(fā)生改變,即為穩(wěn)定的排序,而通過選擇排序算法,兩個大小相等的數(shù)的先后關(guān)系發(fā)生了改變,即為不穩(wěn)定的排序
到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之選擇排序算法的實現(xiàn)與優(yōu)化的文章就介紹到這了,更多相關(guān)Java選擇排序算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot框架集成token實現(xiàn)登錄校驗功能
這篇文章主要為大家詳細介紹了SpringBoot框架集成token實現(xiàn)登錄校驗功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-08-08利用hadoop查詢兩兩之間有共同好友及他倆的共同好友都是誰
一想到要實現(xiàn)求共同好友的功能,很多人都會想到redis來實現(xiàn)。但是redis存儲和數(shù)據(jù)和計算時需要耗費較多的內(nèi)存資源。所以文本將介紹另一種方法,即利用Hadoop中的MapReduce來實現(xiàn),感興趣的可以了解一下2022-01-01詳解Java如何在CompletableFuture中實現(xiàn)日志記錄
這篇文章主要為大家詳細介紹了一種slf4j自帶的MDC類,來記錄完整的請求日志,和在CompletableFuture異步線程中如何保留鏈路id,需要的可以參考一下2023-04-04Redisson 分布式延時隊列 RedissonDelayedQueue 運行流程
這篇文章主要介紹了Redisson分布式延時隊列 RedissonDelayedQueue運行流程,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09