直接插入排序
直接插入排序就是將待排序的值,逐一按元素的大小插入前面的有序序列
例如對-23,45,2,-45,9,5,3,65,-24進行直接插入排序,我們可以看成將45,2,-45,9,5,3,65,-24逐步插入-23的序列
package sort;
public class Demo6 {
public static void main(String[] args) {
int[] num = new int[]{-23,45,2,-45,9,5,3,65,-24};
sort(num);
for (int i = 0; i < num.length; i++) {
System.out.print(num[i]+" ");
}
}
public static void sort(int[] data){
int tmp;//暫時保存待插入的值
//從第2個開始,進行n-1的插入操作
for (int i = 1; i < data.length; i++) {
//若待插入的值比前面有序序列的最大值都大,則說明現在就是有序的
if(data[i]<data[i-1]){
tmp = data[i];
int j = i-1;
for (; j >=0&&data[j]>tmp; j--) {
data[j+1] = data[j];//把數據往後移動
}
data[j+1] = tmp;//退出循環時候,j指向的數值比tmp小,或者j<0
}
}
}
}
折半插入排序
折半插入排序是對直接插入排序的一種改進,直接插入排序中0到i-1有序的,折半插入排序就是用折半查找迅速找到需要插入的地方,而不用從i-1開始逐一向前比較。
使用折半查找查找3應該插入的位置,
1. low=0 hight=6 mid=(low+hight)/2=3
因爲data[3]<=data[7],說明應該插入的位置在4-6之間
2. low=mid+1=3+1=4 hight=6 mid=(low+hight)/2=5
因爲data[5]>data[7]說明應該插入的位置在4到5間
3 low=4 hight=mid-1=5 mid=(4+5)/2=4
因爲data[4]>data[7]所以插入的位置是4,但是此時折半查找並沒有結束
4 low=4 hight=mid-1=3 因爲此時low>hight所以折半折半查找結束
low的位置便是應該插入的位置(該位置滿足data[low]>待插入的值,data[hight]<=待插入的值,或者hight爲-1,也就是插入的位置爲0)
5 將low到i-1的數字都往後移動騰出low的位置將插入值插入,注意備份i位置的值避免被覆蓋後找不回待插入值。
package sort;
public class Demo7 {
public static void main(String[] args) {
int[] data = new int[]{-23,45,2,-45,9,5,3,65,-24};
sort(data);
for (int i = 0; i < data.length; i++) {
System.out.print(data[i]+" ");
}
}
public static void sort(int[] data){
int low,hight,mid;
int tmp;//備份存儲待插入的值
for (int i = 1; i < data.length; i++) {
if(data[i]<data[i-1]){
tmp = data[i];
low = 0;
hight = i-1;
while(low<=hight){
mid = (low+hight)/2;
if(data[mid]<=tmp){ //當中間值小於等於待插入的值,搜索[mid+1,hight]區間
low = mid +1;
}else{
hight = mid - 1; //當中間值小於等於待插入的值,搜索[low,mid-1]區間
}
}
//將[low,i-1]區間的值後移動
for (int j = i-1; j >= low; j--) {
data[j+1] = data[j];
}
//待插入的值插入
data[low] =tmp;
}
}
}
}
希爾排序(Shell排序)
Shell排序是對直接插入排序的改進,它通過加大插入排序中元素之間的間隔,並在這些有間隔的元素進行插入排序,使得數據項跨度移動,不用一步一步往前比較和移動。
Shell排序算法的關鍵就在於確定h序列的值,h就是間隔多少,序列最小值爲1(這時就是直接插入排序),它們存在h=3*h+1的關係。當對一個數列進行Shell排序時,h的值爲多少開始比較合適?h剛好大於數列長度除於3。
int h=1;
while(h<=arrayLength/3){
h = 3*h+1;
}
//得到的h的值就是Shell排序的增量
得到了Shell排序的增量h序列值後,就從第h個後面數字開始對前面間隔h的值進行插入排序。
例如對-23,45,2,-45,9,5,3,65,-24進行Shell排序
1.長度爲9,則可以計算出增量爲4
2.從第4個後面數字(這裏就是9)開始對前面間隔4的值進行插入排序
package sort;
public class Demo5 {
public static void main(String[] args) {
int[] num = new int[]{-23,45,2,-45,9,5,3,65,-24};
sort(num);
}
public static void sort(int[] data){
int h = 1;//增量最小爲1
int tmp;//存儲待插入的值
while(h<=data.length/3){ //計算Shell的最大增量
h = h * 3 + 1;
}
while(h>=1){
//從第h後面的數字開始對前面的間隔爲h的數字進行插入排序,也就是從第h+1個開始,下標爲h
for(int i = h; i<data.length; i++){
tmp = data[i];
if(data[i-h]>tmp){
int j = i-h;
//對前面的間隔爲h的數字進行插入排序,,,當爲1時就是直接插入排序了
for (; j>=0&&data[j]>tmp; j=j-h) {
data[j+h] = data[j];//數據往後移動,間隔爲h
}
data[j+h] = tmp;//這裏加上h是因爲循環最後還減多了一個h
}
}
h = (h-1)/3;//重新計算h的值,尋找小一點的增量
//打印出來看看,每一趟的Shell排序
for (int j = 0; j < data.length; j++) {
System.out.print(data[j]+" ");
}
System.out.println();
}
}
}
三種插入排序的時間複雜度和空間複雜度
插入排序 | 時間複雜度 | 空間複雜度 |
---|---|---|
直接插入排序 | O(n^2) | O(1) |
折半插入排序 | O(n^2) | O(1) |
希爾排序 | O(n^3/2)~O(n^7/6) | O(1) |
——————————————————————————–
關注微信公衆號“閱享屋”可獲取900G IT教學視頻和JAVA、前端電子書籍