十大经典排序算法
冒泡排序
排序(假設(shè)從小到大)的步驟如下:
- 從頭開始,比較相鄰的兩個(gè)數(shù),如果第一個(gè)數(shù)比第二個(gè)數(shù)大,那么就交換它們位置。
- 從開始到最后一對(duì)比較完成,一輪結(jié)束后,最后一個(gè)元素的位置已經(jīng)確定。
- 除了最后一個(gè)元素以外,前面的所有未排好序的元素重復(fù)前面兩個(gè)步驟。
- 重復(fù)前面 1 ~ 3 步驟,直到所有元素都已經(jīng)排好序。
選擇排序
排序的步驟如下:
- 從第一個(gè)元素開始,遍歷其后面的元素,找出其后面比它更小的且最小的元素,若有,則兩者交換,保證第一個(gè)元素最小。
- 對(duì)第二個(gè)元素一樣,遍歷其后面的元素,找出其后面比它更小的且最小的元素,若存在,則兩者交換,保證第二個(gè)元素在未排序的數(shù)中(除了第一個(gè)元素)最小。
- 依次類推,直到最后一個(gè)元素,那么數(shù)組就已經(jīng)排好序了。
插入排序
選擇排序是每次選擇出最小的放到已經(jīng)排好的數(shù)組后面,而插入排序是依次選擇一個(gè)元素,插入到前面已經(jīng)排好序的數(shù)組中間,確保它處于正確的位置,當(dāng)然,這是需要已經(jīng)排好的順序數(shù)組不斷移動(dòng)。步驟描述如下:
步驟描述如下:
- 從第一個(gè)元素開始,可以認(rèn)為第一個(gè)元素已經(jīng)排好順序。
- 取出后面一個(gè)元素 n,在前面已經(jīng)排好順序的數(shù)組里從尾部往頭部遍歷,假設(shè)正在遍歷的元素為 nums[i],如果 num[i] > n,那么將 nums[i] 移動(dòng)到后面一個(gè)位置,直到找到已經(jīng)排序的元素小于或者等于新元素的位置,將 n 放到新騰空出來的位置上。如果沒有找到,那么 nums[i] 就是最小的元素,放在第一個(gè)位置。
- 重復(fù)上面的步驟 2,直到所有元素都插入到正確的位置。
希爾排序
希爾排序(Shell’s Sort)又稱“縮小增量排序”(Diminishing Increment Sort),是插入排序的一種更高效的改進(jìn)版本,同時(shí)該算法是首次沖破 O(n^2n 2 ) 的算法之一
希爾排序基本步驟如下:
- 選擇一個(gè)增量 gap,一般開始是數(shù)組的一半,將數(shù)組元素按照間隔為 gap 分為若干個(gè)小組。
- 對(duì)每一個(gè)小組進(jìn)行插入排序。
- 將 gap 縮小為一半,重新分組,重復(fù)步驟 2(直到 gap 為 1 的時(shí)候基本有序,稍微調(diào)整一下即可)。
快速排序
快速排序比較有趣,選擇數(shù)組的一個(gè)數(shù)作為基準(zhǔn)數(shù),一趟排序,將數(shù)組分割成為兩部分,一部分均小于/等于基準(zhǔn)數(shù),另外一部分大于/等于基準(zhǔn)數(shù)。然后分別對(duì)基準(zhǔn)數(shù)的左右兩部分繼續(xù)排序,直到數(shù)組有序。這體現(xiàn)了分而治之的思想,其中還應(yīng)用到挖坑填數(shù)的策略。
身份證排序
安全局搜索到了一批 (n 個(gè)) 身份證號(hào)碼,希望按出生日期對(duì)它們進(jìn)行從大到小排序,如果有相同日期,則按身份證號(hào)碼大小進(jìn)行排序。身份證號(hào)碼為 18 位的數(shù)字組成,出生日期為第 7 到第 14 位。
package com.ty.test01;import java.io.*; import java.util.ArrayList; import java.util.List;public class CartId {public static void main(String[] args) {BufferedReader bufferedReader= new BufferedReader(new InputStreamReader(System.in));PrintWriter printWriter=new PrintWriter(new OutputStreamWriter(System.out));List<String> strings=new ArrayList<>();try(bufferedReader;printWriter) {int n = Integer.parseInt( bufferedReader.readLine());for (int i = 0; i < n; i++) {strings.add(bufferedReader.readLine());}strings.sort((str1, str2) -> {String sub1 = str1.substring(6, 14);String sub2 = str2.substring(6, 14);if (!sub1.equals(sub2)) {return sub2.compareTo(sub1);}return str2.compareTo(str1);});for (String str : strings) {printWriter.println(str);}} catch (IOException e) {e.printStackTrace();}} }5 466272307503271156 215856472207097978 234804580401078365 404475727700034980 710351408803093165 404475727700034980 234804580401078365 215856472207097978 710351408803093165 466272307503271156歸并排序
前面學(xué)的快速排序,體現(xiàn)了分治的思想,但是不夠典型,而歸并排序則是非常典型的分治策略。歸并的總體思想是先將數(shù)組分割,再分割 … 分割到一個(gè)元素,然后再兩兩歸并排序,做到局部有序,不斷地歸并,直到數(shù)組又被全部合起來。
package com.ty;public class MergeSort {public static void merge(int[]arr,int left,int mid,int right){int[]temp=new int[right-left+1];int l=left;int r=mid+1;int t=0;// 比較左右兩部分的元素,哪個(gè)小,就把那個(gè)元素填入temp中while(l<=mid&&r<=right){if(arr[l]<=arr[r]){temp[t]=arr[l];t++;l++;}else {temp[t] = arr[r];t++;r++;}}// 如果左邊還有元素剩下,則全部合并過去while (l<=mid){temp[t]=arr[l];t++;l++;}// 如果右邊有元素剩下,則把右邊元素合并過去while (r<=right){temp[t]=arr[r];t++;r++;}//把最后的排序結(jié)果復(fù)制到原數(shù)組for(int i=0;i<temp.length;i++){arr[left+i]=temp[i];}}public static void sort(int[]arr,int left,int right){if(left==right){return;}int mid=(left+right)/2;sort(arr,left,mid);sort(arr,mid+1,right);merge(arr,left,mid,right);}public static void printArr(int[] arr){for(int i:arr){System.out.print(i+" ");}}public static void main(String[] args) {int[] arr={101,109,1,10,5,6,3,8,2,0,-1,99};printArr(arr);System.out.println();sort(arr,0,arr.length-1);printArr(arr);} }計(jì)數(shù)排序
計(jì)數(shù)排序,不是基于比較,而是基于計(jì)數(shù),比較適合元素?cái)?shù)值相近且為整數(shù)的情況。
- 遍歷數(shù)組,找出最大值和最小值。
- 根據(jù)最大值和最小值,初始化對(duì)應(yīng)的統(tǒng)計(jì)元素?cái)?shù)量的數(shù)組。
- 遍歷元素,統(tǒng)計(jì)元素個(gè)數(shù)到新的數(shù)組。
- 遍歷統(tǒng)計(jì)的數(shù)組,按照順序輸出排序的數(shù)組元素。
首先先遍歷一遍,找出最小的 min 和最大的元素 max,創(chuàng)建一個(gè)大小為 max - min + 1 的數(shù)組,再遍歷一次,統(tǒng)計(jì)數(shù)字個(gè)數(shù),寫到數(shù)組中。
然后再遍歷一次統(tǒng)計(jì)數(shù)組,將每個(gè)元素置為前面一個(gè)元素加上自身,為什么這樣做呢?
這是為了讓統(tǒng)計(jì)數(shù)組存儲(chǔ)的元素值等于相應(yīng)整數(shù)的最終排序位置,這樣我們就可以做到穩(wěn)定排序,比如下面的 15 對(duì)應(yīng)的是 8,也就是 15 在數(shù)組中出現(xiàn)是第 8 個(gè)元素,從后面開始遍歷,我們就可以保持穩(wěn)定性。
public class CountSort {public static void countSort(int[] nums) {int max = nums[0];int min = nums[0];for (int i = 1; i < nums.length; i++) {if (nums[i] > max) {max = nums[i];}if (nums[i] < min) {min = nums[i];}}System.out.println("min:" + min + ",max:" + max);int count = max - min;int[] countNums = new int[count + 1];for (int i = 0; i < nums.length; i++) {countNums[nums[i] - min]++;}System.out.print("countNums: ");printf(countNums);int sum = 0;// 后面的元素等于前面元素加上自身for (int i = 0; i < count + 1; i++) {sum += countNums[i];countNums[i] = sum;}System.out.print("countNums: ");printf(countNums);int[] newNums = new int[nums.length];for (int i = nums.length - 1; i >= 0; i--) {/*** nums[i] - min 表示原數(shù)組 nums 里面第i位置對(duì)應(yīng)的數(shù)在統(tǒng)計(jì)數(shù)組里面的位置索引*/newNums[countNums[nums[i] - min] - 1] = nums[i];countNums[nums[i] - min]--;}printf(newNums);}public static void printf(int[] nums) {for (int num : nums) {System.out.print(num + " ");}System.out.println("");} }桶排序
桶排序,是指用多個(gè)桶存儲(chǔ)元素,每個(gè)桶有一個(gè)存儲(chǔ)范圍,先將元素按照范圍放到各個(gè)桶中,每個(gè)桶中是一個(gè)子數(shù)組,然后再對(duì)每個(gè)子數(shù)組進(jìn)行排序,最后合并子數(shù)組,成為最終有序的數(shù)組。這其實(shí)和計(jì)數(shù)排序很相似,只不過計(jì)數(shù)排序每個(gè)桶只有一個(gè)元素,而且桶存儲(chǔ)的值為該元素出現(xiàn)的次數(shù)。
桶排序的具體步驟:
- 遍歷數(shù)組,查找數(shù)組的最大最小值,設(shè)置桶的區(qū)間(非必需),初始化一定數(shù)量的桶,每個(gè)桶對(duì)應(yīng)一定的數(shù)值區(qū)間。
- 遍歷數(shù)組,將每一個(gè)數(shù),放到對(duì)應(yīng)的桶中。
- 對(duì)每一個(gè)非空的桶進(jìn)行分別排序(桶內(nèi)部的排序可以選擇 JDK 自帶排序)。
- 將桶中的子數(shù)組拼接成為最終的排序數(shù)組。
堆排序
排序的思路為:
- 將無序的數(shù)組構(gòu)建出一個(gè)大頂堆,也就是上面的元素比下面的元素大。
- 將堆頂?shù)脑睾投训淖钅┪驳脑亟粨Q,將最大元素下沉到數(shù)組的最后面(末端)。
- 重新調(diào)整前面的順序,繼續(xù)交換堆頂?shù)脑睾彤?dāng)前末尾的元素,直到所有元素全部下沉。
基數(shù)排序
假設(shè)有一串?dāng)?shù)字,12,12, 10, 45, 32, 56, 677, 93, 22, 22, 30。
先準(zhǔn)備一個(gè)盒子,里面有0到9的數(shù)據(jù)。
第一步、根據(jù)個(gè)位的數(shù)字將按照順序排列到盒子里:10, 30, 12, 12, 32, 22, 22, 93, 45, 56, 677
第二步、根據(jù)十位的數(shù)字將按照順序排列到盒子里:10, 12, 12, 22, 22, 30, 32, 45, 56, 677, 93
第三步、根據(jù)百位的的數(shù)字按照順序排列到盒子里:10, 12, 12, 22, 22, 30, 32, 45, 56, 93, 677
1、判斷這一串?dāng)?shù)字中最大數(shù)的位數(shù)。
2、因?yàn)槊看闻判蛑挥形粩?shù)不一樣,所以排序的代碼基本相同,用一個(gè)循環(huán)實(shí)現(xiàn)排序。
3、打印排序好的數(shù)。
總結(jié)
- 上一篇: 2020美赛F奖论文(一):摘要、绪论和
- 下一篇: redfish、ipmi返回状态码