Java常用的八種排序算法與代碼實現

?

排序問題一直是程序員工作與面試的重點,今天特意整理研究下與大家共勉!這里列出8種常見的經典排序,基本涵蓋了所有的排序算法。

1.直接插入排序

? ? ? 我們經常會到這樣一類排序問題:把新的數據插入到已經排好的數據列中。將第一個數和第二個數排序,然后構成一個有序序列將第三個數插入進去,構成一個新的有序序列。對第四個數、第五個數……直到最后一個數,重復第二步。如題所示:

直接插入排序(Straight Insertion Sorting)的基本思想:在要排序的一組數中,假設前面(n-1) [n>=2] 個數已經是排好順序的,現在要把第n個數插到前面的有序數中,使得這n個數也是排好順序的。如此反復循環,直到全部排好順序。

代碼實現:

首先設定插入次數,即循環次數,for(int i=1;i<length;i++),1個數的那次不用插入。

設定插入數和得到已經排好序列的最后一個數的位數。insertNum和j=i-1。

從最后一個數開始向前循環,如果插入數小于當前數,就將當前數向后移動一位。

將當前數放置到空著的位置,即j+1。

代碼如下:

復制代碼
 1 public void insertSort(int [] a){2         int len=a.length;//單獨把數組長度拿出來,提高效率3         int insertNum;//要插入的數4         for(int i=1;i<len;i++){//因為第一次不用,所以從1開始5             insertNum=a[i];6             int j=i-1;//序列元素個數7             while(j>=0&&a[j]>insertNum){//從后往前循環,將大于insertNum的數向后移動8                 a[j+1]=a[j];//元素向后移動9                 j--;
10             }
11             a[j+1]=insertNum;//找到位置,插入當前元素
12         }
13     }
復制代碼

2.希爾排序

? ? ? 針對直接插入排序的下效率問題,有人對次進行了改進與升級,這就是現在的希爾排序。希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進版本。希爾排序是非穩定排序算法。

希爾排序是基于插入排序的以下兩點性質而提出改進方法的:

  • 插入排序在對幾乎已經排好序的數據操作時, 效率高, 即可以達到線性排序的效率
  • 但插入排序一般來說是低效的, 因為插入排序每次只能將數據移動一位

如圖所示:

對于直接插入排序問題,數據量巨大時。

將數的個數設為n,取奇數k=n/2,將下標差值為k的數分為一組,構成有序序列。

再取k=k/2 ,將下標差值為k的書分為一組,構成有序序列。

重復第二步,直到k=1執行簡單插入排序。?

代碼實現:

首先確定分的組數。

然后對組中元素進行插入排序。

然后將length/2,重復1,2步,直到length=0為止。

復制代碼
 1 public void sheelSort(int [] a){2         int len=a.length;//單獨把數組長度拿出來,提高效率3         while(len!=0){4             len=len/2;5             for(int i=0;i<len;i++){//分組6                 for(int j=i+len;j<a.length;j+=len){//元素從第二個開始7                     int k=j-len;//k為有序序列最后一位的位數8                     int temp=a[j];//要插入的元素9                     /*for(;k>=0&&temp<a[k];k-=len){
10                         a[k+len]=a[k];
11                     }*/
12                     while(k>=0&&temp<a[k]){//從后往前遍歷
13                         a[k+len]=a[k];
14                         k-=len;//向后移動len位
15                     }
16                     a[k+len]=temp;
17                 }
18             }
19         }
20     }
復制代碼

3.簡單選擇排序

常用于取序列中最大最小的幾個數時。

(如果每次比較都交換,那么就是交換排序;如果每次比較完一個循環再交換,就是簡單選擇排序。)

遍歷整個序列,將最小的數放在最前面。

遍歷剩下的序列,將最小的數放在最前面。

重復第二步,直到只剩下一個數。

代碼實現:

首先確定循環次數,并且記住當前數字和當前位置。

將當前位置后面所有的數與當前數字進行對比,小數賦值給key,并記住小數的位置。

比對完成后,將最小的值與第一個數的值交換。

重復2、3步。

復制代碼
 1 public void selectSort(int[]a){2         int len=a.length;3         for(int i=0;i<len;i++){//循環次數4             int value=a[i];5             int position=i;6             for(int j=i+1;j<len;j++){//找到最小的值和位置7                 if(a[j]<value){8                     value=a[j];9                     position=j;
10                 }
11             }
12             a[position]=a[i];//進行交換
13             a[i]=value;
14         }
15     }
復制代碼

4.堆排序

對簡單選擇排序的優化。

將序列構建成大頂堆。

將根節點與最后一個節點交換,然后斷開最后一個節點。

重復第一、二步,直到所有節點斷開。

?

代碼如下:

復制代碼
 1 public  void heapSort(int[] a){2            int len=a.length;3            //循環建堆  4            for(int i=0;i<len-1;i++){5                //建堆  6                buildMaxHeap(a,len-1-i);7                //交換堆頂和最后一個元素  8                swap(a,0,len-1-i);9            }
10        }
11         //交換方法
12        private  void swap(int[] data, int i, int j) {
13            int tmp=data[i];
14            data[i]=data[j];
15            data[j]=tmp;
16        }
17        //對data數組從0到lastIndex建大頂堆  
18        private void buildMaxHeap(int[] data, int lastIndex) {
19            //從lastIndex處節點(最后一個節點)的父節點開始  
20            for(int i=(lastIndex-1)/2;i>=0;i--){
21                //k保存正在判斷的節點  
22                int k=i;
23                //如果當前k節點的子節點存在  
24                while(k*2+1<=lastIndex){
25                    //k節點的左子節點的索引  
26                    int biggerIndex=2*k+1;
27                    //如果biggerIndex小于lastIndex,即biggerIndex+1代表的k節點的右子節點存在  
28                    if(biggerIndex<lastIndex){
29                        //若果右子節點的值較大  
30                        if(data[biggerIndex]<data[biggerIndex+1]){
31                            //biggerIndex總是記錄較大子節點的索引  
32                            biggerIndex++;
33                        }
34                    }
35                    //如果k節點的值小于其較大的子節點的值  
36                    if(data[k]<data[biggerIndex]){
37                        //交換他們  
38                        swap(data,k,biggerIndex);
39                        //將biggerIndex賦予k,開始while循環的下一次循環,重新保證k節點的值大于其左右子節點的值  
40                        k=biggerIndex;
41                    }else{
42                        break;
43                    }
44                }
45            }
46        }
復制代碼

5.冒泡排序

很簡單,用到的很少,據了解,面試的時候問的比較多!

將序列中所有元素兩兩比較,將最大的放在最后面。

將剩余序列中所有元素兩兩比較,將最大的放在最后面。

重復第二步,直到只剩下一個數。

代碼實現:

設置循環次數。

設置開始比較的位數,和結束的位數。

兩兩比較,將最小的放到前面去。

重復2、3步,直到循環次數完畢。

?

復制代碼
 1  public void bubbleSort(int []a){2            int len=a.length;3            for(int i=0;i<len;i++){4                for(int j=0;j<len-i-1;j++){//注意第二重循環的條件5                    if(a[j]>a[j+1]){6                        int temp=a[j];7                        a[j]=a[j+1];8                        a[j+1]=temp;9                    }
10                }
11            }
12        }
復制代碼

6.快速排序

要求時間最快時。

選擇第一個數為p,小于p的數放在左邊,大于p的數放在右邊。

遞歸的將p左邊和右邊的數都按照第一步進行,直到不能遞歸。

?

復制代碼
 1 public void quickSort(int[]a,int start,int end){2            if(start<end){3                int baseNum=a[start];//選基準值4                int midNum;//記錄中間值5                int i=start;6                int j=end;7                do{8                    while((a[i]<baseNum)&&i<end){9                        i++;
10                    }
11                    while((a[j]>baseNum)&&j>start){
12                        j--;
13                    }
14                    if(i<=j){
15                        midNum=a[i];
16                        a[i]=a[j];
17                        a[j]=midNum;
18                        i++;
19                        j--;
20                    }
21                }while(i<=j);
22                 if(start<j){
23                     quickSort(a,start,j);
24                 }       
25                 if(end>i){
26                     quickSort(a,i,end);
27                 }
28            }
29        }
復制代碼

7.歸并排序

速度僅次于快速排序,內存少的時候使用,可以進行并行計算的時候使用。

選擇相鄰兩個數組成一個有序序列。

選擇相鄰的兩個有序序列組成一個有序序列。

重復第二步,直到全部組成一個有序序列。

復制代碼
 1 public  void mergeSort(int[] a, int left, int right) {  2            int t = 1;// 每組元素個數  3            int size = right - left + 1;  4            while (t < size) {  5                int s = t;// 本次循環每組元素個數  6                t = 2 * s;  7                int i = left;  8                while (i + (t - 1) < size) {  9                    merge(a, i, i + (s - 1), i + (t - 1));  
10                    i += t;  
11                }  
12                if (i + (s - 1) < right)  
13                    merge(a, i, i + (s - 1), right);  
14            }  
15         }  
16        
17         private static void merge(int[] data, int p, int q, int r) {  
18            int[] B = new int[data.length];  
19            int s = p;  
20            int t = q + 1;  
21            int k = p;  
22            while (s <= q && t <= r) {  
23                if (data[s] <= data[t]) {  
24                    B[k] = data[s];  
25                    s++;  
26                } else {  
27                    B[k] = data[t];  
28                    t++;  
29                }  
30                k++;  
31            }  
32            if (s == q + 1)  
33                B[k++] = data[t++];  
34            else  
35                B[k++] = data[s++];  
36            for (int i = p; i <= r; i++)  
37                data[i] = B[i];  
38         }
復制代碼

8.基數排序

用于大量數,很長的數進行排序時。

將所有的數的個位數取出,按照個位數進行排序,構成一個序列。

將新構成的所有的數的十位數取出,按照十位數進行排序,構成一個序列。

?代碼實現:

復制代碼
 1 public void baseSort(int[] a) {2                //首先確定排序的趟數;    3                int max = a[0];4                for (int i = 1; i < a.length; i++) {5                    if (a[i] > max) {6                        max = a[i];7                    }8                }9                int time = 0;
10                //判斷位數;    
11                while (max > 0) {
12                    max /= 10;
13                    time++;
14                }
15                //建立10個隊列;    
16                List<ArrayList<Integer>> queue = new ArrayList<ArrayList<Integer>>();
17                for (int i = 0; i < 10; i++) {
18                    ArrayList<Integer> queue1 = new ArrayList<Integer>();
19                    queue.add(queue1);
20                }
21                //進行time次分配和收集;    
22                for (int i = 0; i < time; i++) {
23                    //分配數組元素;    
24                    for (int j = 0; j < a.length; j++) {
25                        //得到數字的第time+1位數;  
26                        int x = a[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i);
27                        ArrayList<Integer> queue2 = queue.get(x);
28                        queue2.add(a[j]);
29                        queue.set(x, queue2);
30                    }
31                    int count = 0;//元素計數器;    
32                    //收集隊列元素;    
33                    for (int k = 0; k < 10; k++) {
34                        while (queue.get(k).size() > 0) {
35                            ArrayList<Integer> queue3 = queue.get(k);
36                            a[count] = queue3.get(0);
37                            queue3.remove(0);
38                            count++;
39                        }
40                    }
41                }
42         }
復制代碼

新建測試類進行測試

復制代碼
 1 public class TestSort {2     public static void main(String[] args) {3         int []a=new int[10];4         for(int i=1;i<a.length;i++){5             //a[i]=(int)(new Random().nextInt(100));6             a[i]=(int)(Math.random()*100);7         }8         System.out.println("排序前的數組為:"+Arrays.toString(a));9         Sort s=new Sort();
10         //排序方法測試
11         //s.insertSort(a);
12         //s.sheelSort(a);
13         //s.selectSort(a);
14         //s.heapSort(a);
15         //s.bubbleSort(a);
16         //s.quickSort(a, 1, 9);
17         //s.mergeSort(a, 3, 7);
18         s.baseSort(a);
19         System.out.println("排序后的數組為:"+Arrays.toString(a));
20     }
21 
22 }
復制代碼

部分結果如下:

如果要進行比較可已加入時間,輸出排序時間,從而比較各個排序算法的優缺點,這里不再做介紹。

8.總結:

一、穩定性:

 ?? 穩定:冒泡排序、插入排序、歸并排序和基數排序

  不穩定:選擇排序、快速排序、希爾排序、堆排序

二、平均時間復雜度

  O(n^2):直接插入排序,簡單選擇排序,冒泡排序。

  在數據規模較小時(9W內),直接插入排序,簡單選擇排序差不多。當數據較大時,冒泡排序算法的時間代價最高。性能為O(n^2)的算法基本上是相鄰元素進行比較,基本上都是穩定的。

  O(nlogn):快速排序,歸并排序,希爾排序,堆排序。

  其中,快排是最好的, 其次是歸并和希爾,堆排序在數據量很大時效果明顯。

三、排序算法的選擇

  1.數據規模較小

?   (1)待排序列基本序的情況下,可以選擇直接插入排序

?   (2)對穩定性不作要求宜用簡單選擇排序,對穩定性有要求宜用插入或冒泡

  2.數據規模不是很大

  (1)完全可以用內存空間,序列雜亂無序,對穩定性沒有要求,快速排序,此時要付出log(N)的額外空間。

  (2)序列本身可能有序,對穩定性有要求,空間允許下,宜用歸并排序

  3.數據規模很大

??   (1)對穩定性有求,則可考慮歸并排序。

???   (2)對穩定性沒要求,宜用堆排序

  4.序列初始基本有序(正序),宜用直接插入,冒泡

?各算法復雜度如下:

?

?部分參考資料來源于:

  http://blog.csdn.net/without0815/article/details/7697916

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/389998.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/389998.shtml
英文地址,請注明出處:http://en.pswp.cn/news/389998.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

熊貓ai智能機器人量化_機器學習中的熊貓是什么

熊貓ai智能機器人量化Machine learning is a complex discipline. The implementation of machine learning models is now far much easier than it used to be, this is as a result of Machine learning frameworks such as pandas. Wait!! isnt panda an animal? As I rec…

441. 排列硬幣

441. 排列硬幣 你總共有 n 枚硬幣&#xff0c;并計劃將它們按階梯狀排列。對于一個由 k 行組成的階梯&#xff0c;其第 i 行必須正好有 i 枚硬幣。階梯的最后一行 可能 是不完整的。 給你一個數字 n &#xff0c;計算并返回可形成 完整階梯行 的總行數。 示例 1&#xff1a;…

調用百度 Echarts 顯示重慶市地圖

因為 Echarts 官方不再提供地圖數據的下載&#xff0c;在這里保存一份&#xff0c;供日后使用&#xff0c;重慶地圖數據的 JSON 文件在 CSDN 上下載。 <!DOCTYPE html> <html style"height: 100%"><head><meta charset"utf-8"><…

JEESZ-SSO解決方案

2019獨角獸企業重金招聘Python工程師標準>>> 第一節&#xff1a;單點登錄簡介 第一步&#xff1a;了解單點登錄 SSO主要特點是: SSO應用之間使用Web協議(如HTTPS)&#xff0c;并且只有一個登錄入口. SSO的體系中有下面三種角色: 1) User(多個) 2) Web應用(多個) 3) …

女朋友天天氣我怎么辦_關于我的天氣很奇怪

女朋友天天氣我怎么辦帶有扭曲的天氣應用 (A Weather App with a Twist) Is My Weather Weird?? is a weather app with a twist — it offers a simple answer to a common question we’ve all asked. To do this we look at how often weather like today’s used to happ…

Java中length,length(),size()的區別

&#xff08;一&#xff09;區別&#xff1a; ①length&#xff1a;用于算出數組的長度。 ②length&#xff08;&#xff09;&#xff1a;用于找出字符串的長度。 ③size&#xff08;&#xff09;&#xff1a;用于找出泛型集合的元素個數。轉載于:https://www.cnblogs.com/not-…

5895. 獲取單值網格的最小操作數

5895. 獲取單值網格的最小操作數 給你一支股票價格的數據流。數據流中每一條記錄包含一個 時間戳 和該時間點股票對應的 價格 。 不巧的是&#xff0c;由于股票市場內在的波動性&#xff0c;股票價格記錄可能不是按時間順序到來的。某些情況下&#xff0c;有的記錄可能是錯的…

為什么要用Redis

最近閱讀了《Redis開發與運維》&#xff0c;非常不錯。這里對書中的知識整理一下&#xff0c;方便自己回顧一下Redis的整個體系&#xff0c;來對相關知識點查漏補缺。我按照五點把書中的內容進行一下整理&#xff1a;為什么要選擇Redis&#xff1a;介紹Redis的使用場景與使用Re…

第一次馬拉松_成為數據科學家是一場馬拉松而不是短跑

第一次馬拉松Since Data Science became the “Sexiest Job of the 21st Century” the interest in the field has grown tremendously. With it so have the courses available to gain the necessary knowledge. As great as this is, the downside is a field marketed as …

273. 整數轉換英文表示

273. 整數轉換英文表示 將非負整數 num 轉換為其對應的英文表示。 示例 1&#xff1a;輸入&#xff1a;num 123 輸出&#xff1a;"One Hundred Twenty Three" 示例 2&#xff1a;輸入&#xff1a;num 12345 輸出&#xff1a;"Twelve Thousand Three Hundred…

Java-運算符

算術運算符 加法 相加運算符兩側的值- 減法 左操作數減去右操作數* 乘法 相乘操作符兩側的值/ 除法 左操作數除以右操作數&#xff08;int類型的數相除時&#xff0c;會得到int類型的值&#xff0c;如果結果有小數&#xff0c;則小數部分會被舍棄&#xff09;% 模余運算&…

區塊鏈開發公司談區塊鏈在商業上的應用

對于近期正受科技界和資本市場關注的區塊鏈行業&#xff0c;一句話概括說如果互聯網技術解決的是通訊問題的話&#xff0c;區塊鏈技術解決的是信任問題&#xff0c;其在商業領域應用如何呢&#xff1f;我們來從兩個方面去進行剖析。 第一方面&#xff0c;區塊鏈技術可以解決基礎…

ORACLE1.21 PLSQL 01

-- 有了SQL 為什么還需要PL/SQL -- SQL功能很強大&#xff0c;但如果是單1sql語句&#xff0c;沒有流程控制 -- PL/SQL 是什么&#xff1f; --不僅僅實現流程控制&#xff0c;同時保留SQL本身所有的功能 --還提供變量、常量等支持 --提供更多數據類型的支持 --第一&#xff0c;…

云原生數據庫_數據標簽競賽云原生地理空間沖刺

云原生數據庫STAC specification is getting closer to the ver 1.0 milestone, and as such the first virtual Cloud Native Geospatial Sprint is being organized next week. An outreach day is planned on Sep 8th with a series of talks and tutorials for everyone. R…

Linux 下的 hosts文件

2019獨角獸企業重金招聘Python工程師標準>>> hosts 文件 目錄在 /etc/hosts netstat -ntlp //linux 下查看端口 轉載于:https://my.oschina.net/u/2494575/blog/1923074

412. Fizz Buzz

412. Fizz Buzz 給你一個整數 n &#xff0c;找出從 1 到 n 各個整數的 Fizz Buzz 表示&#xff0c;并用字符串數組 answer&#xff08;下標從 1 開始&#xff09;返回結果&#xff0c;其中&#xff1a; answer[i] “FizzBuzz” 如果 i 同時是 3 和 5 的倍數。answer[i] “…

DjangoORM字段介紹

轉載于:https://www.cnblogs.com/cansun/p/8647371.html

黑客獨角獸_雙獨角獸

黑客獨角獸Preface前言 Last week my friend and colleague Srivastan Srivsan’s note on LinkedIn about Mathematics and Data Science opened an excellent discussion. Well, it is not something new; there were debates in the tech domain such as vim v.s emacs to …

38. 外觀數列

38. 外觀數列 給定一個正整數 n &#xff0c;輸出外觀數列的第 n 項。 「外觀數列」是一個整數序列&#xff0c;從數字 1 開始&#xff0c;序列中的每一項都是對前一項的描述。 你可以將其視作是由遞歸公式定義的數字字符串序列&#xff1a; countAndSay(1) “1”countAnd…

JavaScript進階(一)--執行上下文

在下工科生一枚&#xff0c;自認為文筆爛大街&#xff01;本著總結JavaScript原理知識&#xff0c;提升自我寫作水平的目的&#xff0c;提筆寫下這幾篇文章&#xff0c;噴子們高抬貴手?。寫作過程中本系列過程中&#xff0c;我會盡快寫完全部內容&#xff0c;再回過頭來優化補…