日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 数据结构和算法 排序

發布時間:2024/1/8 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 数据结构和算法 排序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

排序算法

        • 排序算法的介紹
      • 算法的時間復雜度
        • **度量一個程序(算法)執行時間的兩種方法**
        • **時間頻度**
        • **時間復雜度**
        • **常見的時間復雜度**
        • 平均時間復雜度和最壞時間復雜度
      • 算法的空間復雜度
        • 基本介紹
      • 排序算法
        • 冒泡排序
        • 選擇排序
        • 插入排序
        • 希爾排序
        • 快速排序
        • 歸并排序
        • 基數排序
        • 相關術語解釋

排序算法的介紹

排序也稱排序算法(Sort Algorithm),排序是將一組數據,依指定的順序進行排列的過程。
排序的分類:

  • 內部排序:<重點>
    指將需要處理的所有數據都加載到內部存儲器中進行排序。
  • 外部排序法:數據量過大,無法全部加載到內存中,需要借助外部存儲(文件等)進行排序。
  • 常見的排序算法分類(見下圖):
  • 算法的時間復雜度

    度量一個程序(算法)執行時間的兩種方法

  • 事后統計的方法:
    這種方法可行, 但是有兩個問題:一是要想對設計的算法的運行性能進行評測,需要實際運行該程序;二是所得時間的統計量依賴于計算機的硬件、軟件等環境因素, 這種方式,要在同一臺計算機的相同狀態下運行,才能比較那個算法速度更快。
    問題:可能花費很長時間;電腦不一樣結果可能不一樣
  • 事前估算的方法:
    通過分析某個算法的時間復雜度來判斷哪個算法更優.
  • 時間頻度

    基本介紹
    時間頻度:一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)。

    例如:


    結論: 在統計一個時間復雜度時,常數項可以忽略

  • 2n+20 和 2n 隨著n 變大,執行曲線無限接近, 20可以忽略
  • 3n+10 和 3n 隨著n 變大,執行曲線無限接近, 10可以忽略


  • 結論: 在統計一個時間復雜度時,可以忽略低次項

  • 2n^2+3n+10 和 2n^2 隨著n 變大, 執行曲線無限接近, 可以忽略 3n+10
  • n^2+5n+20 和 n^2 隨著n 變大,執行曲線無限接近, 可以忽略 5n+20
  • 結論: 在統計一個時間復雜度時,可以忽略系數

  • 隨著n值變大,5n^2+7n 和 3n^2 + 2n ,執行曲線重合, 說明 這種情況下, 5和3可以忽略。
  • 而n^3+5n 和 6n^3+4n ,執行曲線分離,說明多少次方式關鍵
  • 時間復雜度

    基本介紹
    一般情況下,算法中的基本操作語句的重復執行次數是問題規模n的某個函數,用T(n)表示,若有某個輔助函數f(n),使得當n趨近于無窮大時,T(n) / f(n) 的極限值為不等于零的常數,則稱f(n)是T(n)的同數量級函數。記作 T(n)=O( f(n) ),稱O( f(n) ) 為算法的漸進時間復雜度,簡稱時間復雜度。

    注意:T(n) 不同,但時間復雜度可能相同
    如:T(n)=n2+7n+6 與 T(n)=3n2+2n+2 它們的T(n) 不同,但時間復雜度相同,都為O(n2)。

    計算時間復雜度的方法:

  • 用常數1代替運行時間中的所有加法常數 T(n)=n2+7n+6 —> T(n)=n2+7n+1
  • 修改后的運行次數函數中,只保留最高階項 T(n)=n2+7n+1 —> T(n) = n2
  • 去除最高階項的系數 T(n) = n2 —> T(n) = n2 —> O(n2)
  • 常見的時間復雜度

  • 常數階O(1)
  • 對數階O(log2n)
  • 線性階O(n)
  • 線性對數階O(nlog2n)
  • 平方階O(n^2)
  • 立方階O(n^3)
  • k次方階O(n^k)
  • 指數階O(2^n)
  • 常見的算法時間復雜度由小到大依次為:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)< Ο(nk) <Ο(2n),隨著問題規模n的不斷增大,上述時間復雜度不斷增大,算法的執行效率越低

    從圖中可見,我們應該盡可能避免使用指數階的算法


    常見的時間復雜度

  • 常數階O(1)
    無論代碼執行了多少行,只要是沒有循環等復雜結構,那這個代碼的時間復雜度就都是O(1)
  • 上述代碼在執行的時候,它消耗的時候并不隨著某個變量的增長而增長,那么無論這類代碼有多長,即使有幾萬幾十萬行,都可以用O(1)來表示它的時間復雜度。

  • 對數階O(log2n)
  • 說明:在while循環里面,每次都將 i 乘以 2,乘完之后,i 距離 n 就越來越近了。假設循環x次之后,i 就大于 2 了,此時這個循環就退出了,也就是說 2 的 x 次方等于 n,那么 x = log2n也就是說當循環 log2n 次以后,這個代碼就結束了。因此這個代碼的時間復雜度為:O(log2n) 。 O(log2n) 的這個2 時間上是根據代碼變化的,i = i * 3 ,則是 O(log3n) .

  • 線性階O(n)
  • 說明:這段代碼,for循環里面的代碼會執行n遍,因此它消耗的時間是隨著n的變化而變化的,因此這類代碼都可以用O(n)來表示它的時間復雜度

  • 線性對數階O(nlogN)
  • 說明:線性對數階O(nlogN) 其實非常容易理解,將時間復雜度為O(logn)的代碼循環N遍的話,那么它的時間復雜度就是 n * O(logN),也就是了O(nlogN)

    … … … …

    平均時間復雜度和最壞時間復雜度

    算法的空間復雜度

    基本介紹

  • 類似于時間復雜度的討論,一個算法的空間復雜度(Space Complexity)定義為該算法所耗費的存儲空間,它也是問題規模n的函數。
  • 空間復雜度(Space Complexity)是對一個算法在運行過程中臨時占用存儲空間大小的量度。有的算法需要占用的臨時工作單元數與解決問題的規模n有關,它隨著n的增大而增大,當n較大時,將占用較多的存儲單元,例如快速排序和歸并排序算法就屬于這種情況
  • 在做算法分析時,主要討論的是時間復雜度。從用戶使用體驗上看,更看重的程序執行的速度。一些緩存產品(redis, memcache)和算法(基數排序)本質就是用空間換時間.
  • 排序算法

    冒泡排序

    基本介紹

    冒泡排序(Bubble Sorting)的基本思想是:通過對待排序序列從前向后(從下標較小的元素開始),依次比較相鄰元素的值,若發現逆序則交換,使值較大的元素逐漸從前移向后部,就象水底下的氣泡一樣逐漸
    向上冒。

    優化:

    因為排序的過程中,各元素不斷接近自己的位置,如果一趟比較下來沒有進行過交換,就說明序列有序,因此要在排序過程中設置一個標志flag判斷元素是否進行過交換。從而減少不必要的比較。(這里說的優化,可以在冒泡排序寫好后,再進行)

    圖解

    代碼

    package sort; /** @Author: Min* @Date: 2021/10/3* @description*/import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date;public class BubbleSort {public static void main(String[] args) {//測試冒泡排序的速度//給定80000個數據測試int[] arr = new int[80000];for (int i = 0; i < 80000; i++) {arr[i] = (int) (Math.random() * 8000000);//生成[0,8000000)的隨機數組}Date start = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(start);bubbleSort(arr);Date end = new Date();String e = sdf.format(end);System.out.println("排序前:" + s);System.out.println("排序后:" + e);// int arr[] = {3,9,-1,10,-2}; // //為了容易理解,如下是冒泡排序的演變過程 // //第一趟排序.最大的數排在最后 // int temp = 0;//臨時變量 // for (int i = 0; i < arr.length-1; i++) { // //如果前面的數比后面的數大,則交換 // if (arr[i] > arr[i+1]) { // temp = arr[i]; // arr[i] = arr[i+1]; // arr[i+1] = temp; // } // } // System.out.println("第一趟排序后的數組:"); // System.out.println(Arrays.toString(arr)); // // //第二趟排序 // for (int i = 0; i < arr.length-1-1; i++) { // //如果前面的數比后面的數大,則交換 // if (arr[i] > arr[i+1]) { // temp = arr[i]; // arr[i] = arr[i+1]; // arr[i+1] = temp; // } // } // System.out.println("第二趟排序后的數組:"); // System.out.println(Arrays.toString(arr)); // // //第三趟排序 // for (int i = 0; i < arr.length-1-2; i++) { // //如果前面的數比后面的數大,則交換 // if (arr[i] > arr[i+1]) { // temp = arr[i]; // arr[i] = arr[i+1]; // arr[i+1] = temp; // } // } // System.out.println("第三趟排序后的數組:"); // System.out.println(Arrays.toString(arr)); // // //第四趟排序 // for (int i = 0; i < arr.length-1-3; i++) { // //如果前面的數比后面的數大,則交換 // if (arr[i] > arr[i+1]) { // temp = arr[i]; // arr[i] = arr[i+1]; // arr[i+1] = temp; // } // } // System.out.println("第四趟排序后的數組:"); // System.out.println(Arrays.toString(arr));// //代碼優化 // int temp = 0; // for (int j = 0; j < arr.length-1; j++) { // // for (int i = 0; i < arr.length-1-j; i++) { // //如果前面的數比后面的數大,則交換 // if (arr[i] > arr[i+1]) { // temp = arr[i]; // arr[i] = arr[i+1]; // arr[i+1] = temp; // } // } // System.out.println("第"+(j+1)+"趟排序后的數組:"); // System.out.println(Arrays.toString(arr)); // } // // int arr2[] = {3,9,-1,10,20}; // //算法優化 // boolean flag = false;//標識符---表示是否進行過交換 // for (int j = 0; j < arr2.length-1; j++) { // // for (int i = 0; i < arr2.length-1-j; i++) { // //如果前面的數比后面的數大,則交換 // if (arr2[i] > arr2[i+1]) { // flag = true; // temp = arr2[i]; // arr2[i] = arr2[i+1]; // arr2[i+1] = temp; // } // } // System.out.println("第"+(j+1)+"趟排序后的數組:"); // System.out.println(Arrays.toString(arr2)); // if (!flag) { // //某一趟排序中一次都沒有交換過 // break; // } else { // flag = false;//很重要 // //重置,進行下一次的判斷 // } // } // /* // 解析:最后有三趟 // int arr2[] = {3,9,-1,10,20}; // 第1趟排序后的數組:[3, -1, 9, 10, 20]——有交換 // 第2趟排序后的數組:[-1, 3, 9, 10, 20]——有交換 // 第3趟排序后的數組:[-1, 3, 9, 10, 20]——無交換,代碼停止 // */// //測試封裝后的冒泡排序 // int arr3[] = {3,9,-1,10,20}; // bubbleSort(arr3);}//將冒泡排序優化算法封裝public static void bubbleSort(int[] arr) {int temp = 0;boolean flag = false;//標識符---表示是否進行過交換for (int j = 0; j < arr.length-1; j++) {for (int i = 0; i < arr.length-1-j; i++) {//如果前面的數比后面的數大,則交換if (arr[i] > arr[i+1]) {flag = true;temp = arr[i];arr[i] = arr[i+1];arr[i+1] = temp;}} // System.out.println("第"+(j+1)+"趟排序后的數組:"); // System.out.println(Arrays.toString(arr));if (!flag) {//某一趟排序中一次都沒有交換過break;} else {flag = false;//很重要//重置,進行下一次的判斷}}System.out.println(Arrays.toString(arr));} }

    選擇排序

    基本介紹

    選擇式排序也屬于內部排序法,是從欲排序的數據中,按指定的規則選出某一元素,再依規定交換位置后達到排序的目的。

    基本思想:

    圖解

    代碼

    package sort; /** @Author: Min* @Date: 2021/10/4* @description*/import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date;public class SelectSort {public static void main(String[] args) {//測試選擇排序的速度//給定80000個數據測試int[] arr = new int[80000];for (int i = 0; i < 80000; i++) {arr[i] = (int) (Math.random() * 8000000);//生成[0,8000000)的隨機數組}Date start = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(start);selectSort(arr);System.out.println(Arrays.toString(arr));Date end = new Date();String e = sdf.format(end);System.out.println("排序前:" + s);System.out.println("排序后:" + e);// int arr[] = {101,34,119,1}; // System.out.println("原始數據:"); // System.out.println(Arrays.toString(arr)); // selectSort(arr); // System.out.println("排序后:"); // System.out.println(Arrays.toString(arr));}//選擇排序public static void selectSort(int[] arr) {//簡化代碼for (int i = 0; i < arr.length-1; i++) {int minIndex = i;int min = arr[i];for (int j = i + 1; j < arr.length; j++) {if (min > arr[j]) {//如果滿足,說明假定的值不是最小的min = arr[j];//重置minminIndex = j;//重置minIndex}}//將最小值,放在arr[0],即交換if (minIndex != i) {arr[minIndex] = arr[i];arr[i] = min;} // System.out.println("第"+(i+1)+"輪:"); // System.out.println(Arrays.toString(arr));}// //使用逐步推導是方式來 // //第一輪: // //原始的數組: 101,34,119,1 // //第一輪排序: 1,34,119,101 // //算法:簡單->復雜 把一個復雜的算法拆分成簡單的問題,逐步解決 // // int minIndex = 0; // int min = arr[0]; // for (int j = 0 + 1; j < arr.length; j++) { // if (min > arr[j]) { // //如果滿足,說明假定的值不是最小的 // min = arr[j];//重置min // minIndex = j;//重置minIndex // } // } // //將最小值,放在arr[0],即交換 // if (minIndex != 0) { // arr[minIndex] = arr[0]; // arr[0] = min; // } // System.out.println("第一輪:"); // System.out.println(Arrays.toString(arr)); // // //第二輪 // minIndex = 1; // min = arr[1]; // for (int j = 0 + 1; j < arr.length; j++) { // if (min > arr[j]) { // //如果滿足,說明假定的值不是最小的 // min = arr[j];//重置min // minIndex = j;//重置minIndex // } // } // if (minIndex != 1) { // arr[minIndex] = arr[1]; // arr[1] = min; // } // System.out.println("第二輪:"); // System.out.println(Arrays.toString(arr)); // // //第三輪 // minIndex = 2; // min = arr[2]; // for (int j = 0 + 2; j < arr.length; j++) { // if (min > arr[j]) { // //如果滿足,說明假定的值不是最小的 // min = arr[j];//重置min // minIndex = j;//重置minIndex // } // } // if (minIndex != 2) { // arr[minIndex] = arr[2]; // arr[2] = min; // } // System.out.println("第三輪:"); // System.out.println(Arrays.toString(arr));} }

    插入排序

    基本介紹:

    插入式排序屬于內部排序法,是對于欲排序的元素以插入的方式找尋該元素的適當位置,以達到排序的目的。

    插入排序法思想:

    插入排序的基本思想是:把n個待排序的元素看成為一個有序表和一個無序表,開始時有序表中只包含一個元素,無序表中包含有n-1個元素,排序過程中每次從無序表中取出第一個元素,把它的排序碼依次與有序表元素的排序碼進行比較,將它插入到有序表中的適當位置,使之成為新的有序表。

    圖解

    代碼

    package sort; /** @Author: Min* @Date: 2021/10/4* @description*/import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date;public class InsertSort {public static void main(String[] args) { // int[] arr = {101,34,119,1}; // insertSort(arr);//測試插入排序的速度//給定80000個數據測試int[] arr = new int[80000];for (int i = 0; i < 80000; i++) {arr[i] = (int) (Math.random() * 8000000);//生成[0,8000000)的隨機數組}Date start = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(start);insertSort(arr);System.out.println(Arrays.toString(arr));Date end = new Date();String e = sdf.format(end);System.out.println("排序前:" + s);System.out.println("排序后:" + e);}//插入排序public static void insertSort(int[] arr) { // //使用逐步推導的方式 // //第一輪 // //定義待插入的數 // int insertVal = arr[1]; // int insertIndex = 1 - 1;//即arr[1]的前面這個數的下標 // //給insertVal 找到插入的位置 // //說明: // //1.insertIndex >= 0 保證在給insertVal找插入位置,不越界 // //2.insertVal < arr[insertIndex] 待插入的數,還沒有找到插入位置 // //3.就需要將arr[insertIndex]后移 // while (insertIndex >= 0 && insertVal < arr[insertIndex]) { // arr[insertIndex + 1] = arr[insertIndex]; // insertIndex--; // } // //當退出while循環時,說明插入的位置找到,insertIndex +1 // arr[insertIndex + 1] = insertVal; // System.out.println("第一輪插入:"); // System.out.println(Arrays.toString(arr)); // // //第二輪 // insertVal = arr[2]; // insertIndex = 2 - 1; // while (insertIndex >= 0 && insertVal < arr[insertIndex]) { // arr[insertIndex + 1] = arr[insertIndex]; // insertIndex--; // } // arr[insertIndex + 1] = insertVal; // System.out.println("第二輪插入:"); // System.out.println(Arrays.toString(arr)); // // //第san輪 // insertVal = arr[3]; // insertIndex = 3 - 1; // while (insertIndex >= 0 && insertVal < arr[insertIndex]) { // arr[insertIndex + 1] = arr[insertIndex]; // insertIndex--; // } // arr[insertIndex + 1] = insertVal; // System.out.println("第3輪插入:"); // System.out.println(Arrays.toString(arr));//簡化代碼for (int i = 1; i < arr.length; i++) {int insertVal = arr[i];int insertIndex = i-1;while (insertIndex >= 0 && insertVal < arr[insertIndex]) {arr[insertIndex + 1] = arr[insertIndex];insertIndex--;}if (insertIndex+1 == i){//優化arr[insertIndex + 1] = insertVal;} // System.out.println("第"+(i)+"輪插入:"); // System.out.println(Arrays.toString(arr));}} }

    希爾排序

    基本介紹

    希爾排序是希爾(Donald Shell)于1959年提出的一種排序算法。希爾排序也是一種插入排序,它是簡單插入排序經過改進之后的一個更高效的版本,也稱為縮小增量排序。

    基本思想

    希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,算法便終止。

    圖解

    代碼

    • 交換法:
    package sort; /** @Author: Min* @Date: 2021/10/5* @description 希爾排序*/import javax.imageio.metadata.IIOMetadataFormatImpl; import java.text.SimpleDateFormat; import java.time.temporal.Temporal; import java.util.Arrays; import java.util.Date;public class ShellSort {public static void main(String[] args) { // int arr[] = {8,9,1,7,2,3,5,4,6,0}; // System.out.println("原始數據:"); // System.out.println(Arrays.toString(arr)); // shellSort(arr);//測試希爾排序的速度//給定80000個數據測試int[] arr = new int[80000];for (int i = 0; i < 80000; i++) {arr[i] = (int) (Math.random() * 8000000);//生成[0,8000000)的隨機數組}Date start = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(start);shellSort(arr);System.out.println(Arrays.toString(arr));Date end = new Date();String e = sdf.format(end);System.out.println("排序前:" + s);System.out.println("排序后:" + e);}//希爾排序public static void shellSort(int[] arr) {// int temp = 0; // //逐步推導 // //思路:第一輪:先將10個數據分成了5組 10//2=5 // for (int i = 5;i < arr.length;i ++) { // //遍歷各組中的所有元素,(共5組,每組2個元素),步長為5 // for (int j = i - 5; j >= 0; j -= 5) { // //如果當前元素大于加上步長后的那個元素,則交換 // if (arr[j] > arr[j + 5]) { // temp = arr[j]; // arr[j] = arr[j + 5]; // arr[j + 5] = temp; // } // } // } // System.out.println("第一輪:"); // System.out.println(Arrays.toString(arr)); // //第二輪:之前有5組,5//2=2組 // for (int i = 2;i < arr.length;i ++) { // //遍歷各組中的所有元素,(共4組,每組2個元素),步長為2 // for (int j = i - 2; j >= 0; j -= 2) { // //如果當前元素大于加上步長后的那個元素,則交換 // if (arr[j] > arr[j + 2]) { // temp = arr[j]; // arr[j] = arr[j + 2]; // arr[j + 2] = temp; // } // } // } // System.out.println("第二輪:"); // System.out.println(Arrays.toString(arr)); // //第三輪:之前有2組,2//2=1 // for (int i = 1;i < arr.length;i ++) { // //遍歷各組中的所有元素,(共4組,每組2個元素),步長為2 // for (int j = i - 1; j >= 0; j -= 1) { // //如果當前元素大于加上步長后的那個元素,則交換 // if (arr[j] > arr[j + 1]) { // temp = arr[j]; // arr[j] = arr[j + 1]; // arr[j + 1] = temp; // } // } // } // System.out.println("第三輪:"); // System.out.println(Arrays.toString(arr));//代碼簡化int temp = 0;int x = 0;for (int k = arr.length/2; k > 0; k /= 2) {for (int i = k;i < arr.length;i ++) {//遍歷各組中的所有元素,(共5組,每組2個元素),步長為5for (int j = i - k; j >= 0; j -= k) {//如果當前元素大于加上步長后的那個元素,則交換if (arr[j] > arr[j + k]) {temp = arr[j];arr[j] = arr[j + k];arr[j + k] = temp;}}} // System.out.println("第"+ (++x) + "輪:"); // System.out.println(Arrays.toString(arr));}}}
    • 移動法
    //希爾排序——移動法public static void shellSort2(int[] arr) {//增量k,并逐步縮小增量for (int k = arr.length/2; k > 0; k /= 2) {//從第k個元素,諸葛對其所在的組進行直接插入排序for (int i = k; i < arr.length; i++) {int j = i;int temp = arr[j];if (arr[j] > arr[j-k]) {while (j-k >= 0 && temp < arr[j-k]) {//移動arr[j] = arr[j-k];j -= k;}//當退出while后,就給temp找到插入的位置arr[j] = temp;}}}}

    快速排序

    快速排序(Quicksort)是對冒泡排序的一種改進。基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然后再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列

    示意圖:

    代碼

    package sort; /** @Author: Min* @Date: 2021/10/7* @description*/import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date;public class QuickSort {public static void main(String[] args) { // int[] arr = {-9,78,0,23,-56,70,-1,90,5,8,8}; // quickSort(arr,0,arr.length -1);//快速排序速度測試//給定80000個數據測試int[] arr = new int[80000];for (int i = 0; i < 80000; i++) {arr[i] = (int) (Math.random() * 8000000);//生成[0,8000000)的隨機數組}Date start = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(start);quickSort(arr, 0, arr.length - 1);System.out.println(Arrays.toString(arr));Date end = new Date();String e = sdf.format(end);System.out.println("排序前:" + s);System.out.println("排序后:" + e);}public static void quickSort(int[] arr,int left,int right) {int l = left;//左下標int r = right;//右下標//pivot 中軸int pivot = arr[(left + right) / 2];int temp = 0;//臨時變量//while 循環的目的是讓比pivot值小的放到左邊,比它大的放在右邊while (l < r) {//找比pivot小的值放在左邊,遇到大或等于的退出while (arr[l] < pivot) {l += 1;}//找比pivot 大的值放在右邊,遇到小或等于的退出while (arr[r] > pivot) {r -= 1;}if (l >= r) {//說明pivot的左右兩邊的值,已經按照左邊全是小于pivot的值//右邊全部是大于pivot的值break;}//否則交換temp = arr[l];arr[l] = arr[r];arr[r] = temp;//如果交換完后發現pivot=arr[l],則前移if (arr[l] == pivot) {r -= 1;}//如果交換后,發現pivot=arr[r],則后移if (arr[r] == pivot) {l += 1;} // System.out.println(Arrays.toString(arr));}//如果l==r,必須l++,r--,否則出現棧溢出if (l == r) {l += 1;r -= 1;}//向左遞歸if (left < r) {quickSort(arr,left,r);}//向右遞歸if (right > l) {quickSort(arr,l,right);}} }

    歸并排序

    歸并排序介紹:

    歸并排序(MERGE-SORT)是利用歸并的思想實現的排序方法,該算法采用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然后遞歸求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。

    思想示意圖

    說明:
    可以看到這種結構很像一棵完全二叉樹,本文的歸并排序我們采用遞歸去實現(也可采用迭代的方式去實現)。分階段可以理解為就是遞歸拆分子序列的過程。

    代碼

    package sort; /** @Author: Min* @Date: 2021/10/7* @description*/import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date;public class MergetSort {public static void main(String[] args) { // int arr[] ={8,4,5,7,1,3,6,2}; // int temp[] = new int[arr.length];//歸并排序需要一個額外的空間 // mergeSort(arr,0,arr.length-1,temp); // System.out.println(Arrays.toString(arr));//給定80000個數據測試int[] arr = new int[80000];int temp[] = new int[arr.length];//歸并排序需要一個額外的空間for (int i = 0; i < 80000; i++) {arr[i] = (int) (Math.random() * 8000000);//生成[0,8000000)的隨機數組}Date start = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(start);mergeSort(arr,0,arr.length-1,temp );System.out.println(Arrays.toString(arr));Date end = new Date();String e = sdf.format(end);System.out.println("排序前:" + s);System.out.println("排序后:" + e);}//分+合的方法public static void mergeSort(int[] arr,int left,int right,int[] temp) {if (left < right) {int mid = (left + right) / 2;//中間索引//向左遞歸進行分解mergeSort(arr,left,mid,temp);//向右遞歸進行分解mergeSort(arr,mid+1,right,temp);//每分解一次就合并一次merge(arr,left,mid,right,temp);}}//合并的方法/**@param arr 排序的原始數組* @param left 左邊的有序序列的初始索引* @param mid 中間索引* @param right 右邊索引* @param temp 做中轉的數組*/public static void merge(int []arr,int left,int mid,int right,int[] temp) {int i = left;//初始化i,左邊有序序列的初始索引int j = mid + 1;//初始化j,右邊有序序列的初始索引int t = 0;//指向temp數組的當前索引//先把左右兩邊(有序)的數據按照規則填充到temp數組//直到左右兩邊的有序數組序列右一邊全部處理完畢為止while (i <= mid && j <= right) {//如果左邊的有序序列的當前元素,小于等于右邊有序序列的當前元素//即將左邊的當前元素,//然后t++,i++if (arr[i] <= arr[j]) {temp[t] = arr[i];t ++;i ++;} else {temp[t] = arr[j];t ++;j ++;}}//把剩余數據的一邊的數據依次全部填充到tempwhile (i <= mid) {//左邊的有序序列還有剩余元素,就全部填充到temptemp[t] = arr[i];t ++;i ++;}while (j <= right) {//右邊的有序序列還有剩余的元素,就全部填充到temptemp[t] = arr[j];t ++;j ++;}//將temp數組的一邊數據一次全部填充到temp//注意:并不是每次都拷貝所有t = 0;int tempLeft = left;while (tempLeft <= right) {//arr[tempLeft] = temp[t];t ++;tempLeft ++;}}}

    基數排序

    基數排序(桶排序)介紹:

  • 基數排序(radix sort)屬于“分配式排序”(distribution sort),又稱“桶子法”(bucket sort)或bin sort,顧名思義,它是通過鍵值的各個位的值,將要排序的元素分配至某些“桶”中,達到排序的作用
  • 基數排序法是屬于穩定性的排序,基數排序法的是效率高的穩定性排序法
  • 基數排序(Radix Sort)是桶排序的擴展
  • 基數排序是1887年赫爾曼·何樂禮發明的。它是這樣實現的:將整數按位數切割成不同的數字,然后按每個位數分別比較。
  • 基本思想
    將所有待比較數值統一為同樣的數位長度,數位較短的數前面補零。然后,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以后, 數列就變成一個有序序列。

    示意圖

    第一輪:
    第二輪:


    第三輪:

    一共要多少輪?取決于數據里面最大數的位數

    代碼

    package sort; /** @Author: Min* @Date: 2021/10/9* @description*/import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date;import static java.lang.Math.pow;public class RadixSort {public static void main(String[] args) { // int arr[] = {53,3,542,748,14,214,8452,2366,961212545,45461321}; // radixSort(arr); // System.out.println(Arrays.toString(arr));//給定80000個數據測試int[] arr = new int[80000];int temp[] = new int[arr.length];for (int i = 0; i < 80000; i++) {arr[i] = (int) (Math.random() * 8000000);//生成[0,8000000)的隨機數組}Date start = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(start);radixSort(arr);System.out.println(Arrays.toString(arr));Date end = new Date();String e = sdf.format(end);System.out.println("排序前:" + s);System.out.println("排序后:" + e);}//基數排序public static void radixSort(int[] arr) {//代碼簡化int[][] bucket = new int[10][arr.length];//為了記錄每個桶中實際存放了多少數據,定義一個一維數組來記錄各個桶每次放入的數據是個數//*原來桶中的數據不會刪除,新數據覆蓋.....int[] bucketElementCounts = new int[10];//得到數組中的最大位數的值int max = arr[0];for (int i = 1; i < arr.length; i++) {if (arr[i] > max) {max = arr[i];}}//得到最大位數int length = (max + "").length();for (int j = 0; j < length; j++) {for (int i = 0;i < arr.length;i ++) {int digitOfElement = arr[i] / (int)(pow(10,j)) % 10 ;//放入到對應的桶中bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];bucketElementCounts[digitOfElement] ++ ;//bucketElementCounts[digitOfElement]初始化為0} // for (int i = 0,n = 1; i < arr.length; i++,n *= 10) { // int digitOfElement = arr[i] / (int)(pow(10,j)) % 10 ; // //放入到對應的桶中 // bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i]; // bucketElementCounts[digitOfElement] ++ ;//bucketElementCounts[digitOfElement]初始化為0 // }//按照桶的順序,將數據放回數組int index = 0;//遍歷每一個桶,并將桶中的數據,放入到原數組for (int k = 0;k < bucketElementCounts.length;k ++) {//如果桶中有數據才放入到原數組if (bucketElementCounts[k] != 0) {//說明有數據//此時循環放入數據for (int l = 0;l < bucketElementCounts[k];l ++) {//取出元素放到arrarr[index] = bucket[k][l];//第k個桶的l個元素index++;}}bucketElementCounts[k] = 0;//置0} // System.out.println("第"+j+"輪:" + Arrays.toString(arr));}// //定義一個二維數組,表示10個桶,每個桶就是一個一維數組 // //*為了防止溢出,每個一維數組的大小為 arr.length // int[][] bucket = new int[10][arr.length]; // //為了記錄每個桶中實際存放了多少數據,定義一個一維數組來記錄各個桶每次放入的數據是個數 // //*原來桶中的數據不會刪除,新數據覆蓋..... // int[] bucketElementCounts = new int[10]; // // //第一輪 ——對個位進行排序 // for (int i = 0;i < arr.length;i ++) { // //取出個位 // int digitOfElement = arr[i] % 10;//得到元素個位的值 // //放入到對應的桶中 // bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i]; // bucketElementCounts[digitOfElement] ++ ;//bucketElementCounts[digitOfElement]初始化為0 // } // //按照桶的順序,將數據放回數組 // int index = 0; // //遍歷每一個桶,并將桶中的數據,放入到原數組 // for (int k = 0;k < bucketElementCounts.length;k ++) { // //如果桶中有數據才放入到原數組 // if (bucketElementCounts[k] != 0) {//說明有數據 // //此時循環放入數據 // for (int l = 0;l < bucketElementCounts[k];l ++) { // //取出元素放到arr // arr[index] = bucket[k][l];//第k個桶的l個元素 // index++; // } // } // bucketElementCounts[k] = 0;//置0 // } // System.out.println("第一輪:" + Arrays.toString(arr)); // //第二輪 ——對個位進行排序 // for (int i = 0;i < arr.length;i ++) { // //取出十位 // int digitOfElement = arr[i] /10 % 10;//得到元素十位的值 // //放入到對應的桶中 // bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i]; // bucketElementCounts[digitOfElement] ++ ;//bucketElementCounts[digitOfElement]初始化為0 // } // //按照桶的順序,將數據放回數組 // index = 0; // //遍歷每一個桶,并將桶中的數據,放入到原數組 // for (int k = 0;k < bucketElementCounts.length;k ++) { // //如果桶中有數據才放入到原數組 // if (bucketElementCounts[k] != 0) {//說明有數據 // //此時循環放入數據 // for (int l = 0;l < bucketElementCounts[k];l ++) { // //取出元素放到arr // arr[index] = bucket[k][l];//第k個桶的l個元素 // index++; // } // } // bucketElementCounts[k] = 0;//置0 // } // System.out.println("第二輪:" + Arrays.toString(arr)); // //第三輪 ——對個位進行排序 // for (int i = 0;i < arr.length;i ++) { // //取出百位 // int digitOfElement = arr[i] /100 % 10;//得到元素百位的值 // //放入到對應的桶中 // bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i]; // bucketElementCounts[digitOfElement] ++ ;//bucketElementCounts[digitOfElement]初始化為0 // } // //按照桶的順序,將數據放回數組 // index = 0; // //遍歷每一個桶,并將桶中的數據,放入到原數組 // for (int k = 0;k < bucketElementCounts.length;k ++) { // //如果桶中有數據才放入到原數組 // if (bucketElementCounts[k] != 0) {//說明有數據 // //此時循環放入數據 // for (int l = 0;l < bucketElementCounts[k];l ++) { // //取出元素放到arr // arr[index] = bucket[k][l];//第k個桶的l個元素 // index++; // } // } // // } // System.out.println("第三輪:" + Arrays.toString(arr));} }

    相關術語解釋

    總結

    以上是生活随笔為你收集整理的java 数据结构和算法 排序的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。