用Java實現(xiàn)希爾排序的示例
更新時間:2013年11月14日 11:44:33 作者:
問題:現(xiàn)有一段程序S,可以對任意n個數(shù)進行排序。如果現(xiàn)在需要對n^2個數(shù)進行排序,最少需要調(diào)用S多少次?只允許調(diào)用S,不可以做別的操作。我們用希爾排序來做解決這個
一.理論準備
希爾排序(Shell Sort)是插入排序的一種,是針對直接插入排序算法的改進,是將整個無序列分割成若干小的子序列分別進行插入排序,希爾排序并不穩(wěn)定。該方法又稱縮小增量排序,因DL.Shell于1959年提出而得名。
基本思想:先取一個小于n的整數(shù)d1作為第一個增量,把文件的全部記錄分成d1個組。所有距離為d1的倍數(shù)的記錄放在同一個組中。先在各組內(nèi)進行直接插入排序;然后,取第二個增量d2<d1重復上述的分組和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有記錄放在同一組中進行直接插入排序為止。
希爾排序的時間性能優(yōu)于直接插入排序的原因:
①當文件初態(tài)基本有序時直接插入排序所需的比較和移動次數(shù)均較少。
②當n值較小時,n和n2的差別也較小,即直接插入排序的最好時間復雜度O(n)和最壞時間復雜度0(n2)差別不大。
③在希爾排序開始時增量較大,分組較多,每組的記錄數(shù)目少,故各組內(nèi)直接插入較快,后來增量di逐漸縮小,分組數(shù)逐漸減少,而各組的記錄數(shù)目逐漸增多,但由于已經(jīng)按di-1作為距離排過序,使文件較接近于有序狀態(tài),所以新的一趟排序過程也較快。
因此,希爾排序在效率上較直接插人排序有較大的改進。
增量序列的選擇:Shell排序的執(zhí)行時間依賴于增量序列。
好的增量序列的共同特征(查到的資料都這么講):
① 最后一個增量必須為1;
② 應該盡量避免序列中的值(尤其是相鄰的值)互為倍數(shù)的情況。
看到了這個,我想試試希爾排序,就學學。
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[]{44,33,99,10,30,20,59,78,23,48};
System.out.print("排序前:");
for(int o: arr) {
System.out.print(o+" ");
}
System.out.println();
shellSort(arr);
System.out.print("排序后:");
for(int o: arr) {
System.out.print(o+" ");
}
System.out.println();
}
private static void shellSort(int[] arr) {
int j;
int len = arr.length;
for(int val=len>>1; val>0; val>>=1) {
//下面是對本次的所有分組做直接插入排序
for(int i=val; i<len; i++) {
int temp = arr[i];
/*
* 為什么每次都用temp比較呢?
* 因為直接插入就是找到temp的合適位置。
* 為什么temp<arr[j-val]這個條件可以放在for內(nèi)呢?
* 因為原來的組內(nèi)數(shù)據(jù)已經(jīng)有序,找到位置就停止便是。
* 不甚理解的去看直接插入排序吧。
*/
for(j=i; j>=val&&temp<arr[j-val]; j-=val) {
/*
* 為什么是arr[j-val]不是arr[j]呢?
* 因為j=i開始的,而且條件是j>=val&&temp<arr[j-val]
*/
arr[j] = arr[j-val];
}
/*
* 注意不是arr[i] = temp
* 直接插入排序也是這樣的。
* 為什么呢?
* 因為j是位置,i是待插入元素
*/
arr[j] = temp;
}
}
}
}
三.問題
希爾排序一定正確么?換句話說如何選取增量序列才能保證正確(包括長度、值)?是的,最后一次只要保證增量是1就ok(不管序列長度,只不過效率就低了),若是序列只有1,那就是直接插入排序了,不知道對否。
希爾排序(Shell Sort)是插入排序的一種,是針對直接插入排序算法的改進,是將整個無序列分割成若干小的子序列分別進行插入排序,希爾排序并不穩(wěn)定。該方法又稱縮小增量排序,因DL.Shell于1959年提出而得名。
基本思想:先取一個小于n的整數(shù)d1作為第一個增量,把文件的全部記錄分成d1個組。所有距離為d1的倍數(shù)的記錄放在同一個組中。先在各組內(nèi)進行直接插入排序;然后,取第二個增量d2<d1重復上述的分組和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有記錄放在同一組中進行直接插入排序為止。
希爾排序的時間性能優(yōu)于直接插入排序的原因:
①當文件初態(tài)基本有序時直接插入排序所需的比較和移動次數(shù)均較少。
②當n值較小時,n和n2的差別也較小,即直接插入排序的最好時間復雜度O(n)和最壞時間復雜度0(n2)差別不大。
③在希爾排序開始時增量較大,分組較多,每組的記錄數(shù)目少,故各組內(nèi)直接插入較快,后來增量di逐漸縮小,分組數(shù)逐漸減少,而各組的記錄數(shù)目逐漸增多,但由于已經(jīng)按di-1作為距離排過序,使文件較接近于有序狀態(tài),所以新的一趟排序過程也較快。
因此,希爾排序在效率上較直接插人排序有較大的改進。
增量序列的選擇:Shell排序的執(zhí)行時間依賴于增量序列。
好的增量序列的共同特征(查到的資料都這么講):
① 最后一個增量必須為1;
② 應該盡量避免序列中的值(尤其是相鄰的值)互為倍數(shù)的情況。
看到了這個,我想試試希爾排序,就學學。
復制代碼 代碼如下:
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[]{44,33,99,10,30,20,59,78,23,48};
System.out.print("排序前:");
for(int o: arr) {
System.out.print(o+" ");
}
System.out.println();
shellSort(arr);
System.out.print("排序后:");
for(int o: arr) {
System.out.print(o+" ");
}
System.out.println();
}
private static void shellSort(int[] arr) {
int j;
int len = arr.length;
for(int val=len>>1; val>0; val>>=1) {
//下面是對本次的所有分組做直接插入排序
for(int i=val; i<len; i++) {
int temp = arr[i];
/*
* 為什么每次都用temp比較呢?
* 因為直接插入就是找到temp的合適位置。
* 為什么temp<arr[j-val]這個條件可以放在for內(nèi)呢?
* 因為原來的組內(nèi)數(shù)據(jù)已經(jīng)有序,找到位置就停止便是。
* 不甚理解的去看直接插入排序吧。
*/
for(j=i; j>=val&&temp<arr[j-val]; j-=val) {
/*
* 為什么是arr[j-val]不是arr[j]呢?
* 因為j=i開始的,而且條件是j>=val&&temp<arr[j-val]
*/
arr[j] = arr[j-val];
}
/*
* 注意不是arr[i] = temp
* 直接插入排序也是這樣的。
* 為什么呢?
* 因為j是位置,i是待插入元素
*/
arr[j] = temp;
}
}
}
}
三.問題
希爾排序一定正確么?換句話說如何選取增量序列才能保證正確(包括長度、值)?是的,最后一次只要保證增量是1就ok(不管序列長度,只不過效率就低了),若是序列只有1,那就是直接插入排序了,不知道對否。
相關文章
Mybatis-Plus3.2.0 MetaObjectHandler 無法進行公共字段全局填充
這篇文章主要介紹了Mybatis-Plus3.2.0 MetaObjectHandler 無法進行公共字段全局填充,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-11-11
詳解使用Mybatis-plus + velocity模板生成自定義的代碼
這篇文章主要介紹了詳解使用Mybatis-plus + velocity模板生成自定義的代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03
spring cloud consul使用ip注冊服務的方法示例
這篇文章主要介紹了spring cloud consul使用ip注冊服務的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-03-03
Maven編譯錯誤:程序包com.sun.*包不存在的三種解決方案
J2SE中的類大致可以劃分為以下的各個包:java.*,javax.*,org.*,sun.*,本文文章主要介紹了maven編譯錯誤:程序包com.sun.xml.internal.ws.spi不存在的解決方案,感興趣的可以了解一下2024-02-02
在spring boot中使用java線程池ExecutorService的講解
今天小編就為大家分享一篇關于在spring boot中使用java線程池ExecutorService的講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03

