算法入門篇四 桶排序

桶排序

計數排序(基于統計)

  • 要求數據是有限的,和數據狀況有關,比如對于200個人統計他們的年齡分布,這個時候需要申請200個桶,因此對于輸入數據的規模有限制,如果輸入規模是不定的,空間申請就會很麻煩。

基數排序

思想

  • 要求排序的數字都是十進制的數字,找到最高位的數字,對于其中不滿足位數的數字前面補0,例如【100,23,34】就需要改寫成【100,023,034】的形式。
  • 準備和數字相同數目的桶(類比于先進先出的隊列),所有數字按照個位數字進桶,然后按照從左往右的次序依次往出倒數字,如果一個桶內有多個數字按照次序(隊列)倒數,再按照十位數字進桶,原理和先前類似,倒出;再按照百位數字進桶,出桶。最后的次序是從小到大的。

落地

  • 初始數組為【23,13,3,24,23,14】,申請兩個棧,一個為count,一個是help。count按照次序分別是【0,1,2,3,4,5,6,7,8,9】這個用于統計對應的數字的個數,比如上面這個例子的話,個位是3的個數有4個,個位是4的個數有3個。而help指定的是數組中元素的個數。此時一個6個元素,所以將help的大小設置為6。
  • ?統計完對應的數字數字之后,得到的count為【0,0,0,4,2,0,0,0,0,0】,對其進行加工,對應元素的位置等于自身的值+前面的元素值。如果是0號位置就是本身,1號就是0+0,2號是0+0;3號是4+0;4號是4+0;5號是6+0;依次類推剩余元素的值都是6。經過加工后的count數組含義就是小于等于相應位置上元素的個數。比如小于等于3的有三個元素;小于等于5,6,7,8,9的有6個元素。

操作過程?

  • 從右往左遍歷,第一個元素是14,個位數小于等于6的有6個,所以將14填寫在help的5位置上,并且將count數組中的4對應的6減1,變成5。
  • 下一個元素是23,個位元素對應的是3,查詢count數組,小于等于3的元素有四個,因此將23填寫在help數組的3號位置,count中3號位置的4減1;
  • 下一個元素是24,?個位元素對應的是4,查詢count數組,小于等于4的元素有5個,因此將24填寫在help數組的4號位置,count中4號位置的5減1;
  • 下一個元素是3,?個位元素對應的是3,查詢count數組,小于等于3的元素有3個,因此將3填寫在help數組的2號位置,count中3號位置的3減1;
  • 下一個元素是13,?個位元素對應的是3,查詢count數組,小于等于3的元素有2個,因此將3填寫在help數組的1號位置,count中3號位置的2減1;
  • 下一個元素是23,?個位元素對應的是3,查詢count數組,小于等于3的元素有1個,因此將3填寫在help數組的0號位置,count中3號位置的1減1;

完整代碼

package class03;import java.util.Arrays;public class Code02_RadixSort {// only for no-negative valuepublic static void radixSort(int[] arr) {if (arr == null || arr.length < 2) {return;}radixSort(arr, 0, arr.length - 1, maxbits(arr));}public static int maxbits(int[] arr) {int max = Integer.MIN_VALUE;for (int i = 0; i < arr.length; i++) {max = Math.max(max, arr[i]);}int res = 0;while (max != 0) {res++;max /= 10;}return res;}// arr[begin..end]排序public static void radixSort(int[] arr, int L, int R, int digit) {final int radix = 10;int i = 0, j = 0;// 有多少個數準備多少個輔助空間int[] bucket = new int[R - L + 1];for (int d = 1; d <= digit; d++) { // 有多少位就進出幾次// 10個空間// count[0] 當前位(d位)是0的數字有多少個// count[1] 當前位(d位)是(0和1)的數字有多少個// count[2] 當前位(d位)是(0、1和2)的數字有多少個// count[i] 當前位(d位)是(0~i)的數字有多少個int[] count = new int[radix]; // count[0..9]for (i = L; i <= R; i++) {j = getDigit(arr[i], d);count[j]++;}for (i = 1; i < radix; i++) {count[i] = count[i] + count[i - 1];}for (i = R; i >= L; i--) {j = getDigit(arr[i], d);bucket[count[j] - 1] = arr[i];count[j]--;}for (i = L, j = 0; i <= R; i++, j++) {arr[i] = bucket[j];}}}public static int getDigit(int x, int d) {return ((x / ((int) Math.pow(10, d - 1))) % 10);}// for testpublic static void comparator(int[] arr) {Arrays.sort(arr);}// for testpublic static int[] generateRandomArray(int maxSize, int maxValue) {int[] arr = new int[(int) ((maxSize + 1) * Math.random())];for (int i = 0; i < arr.length; i++) {arr[i] = (int) ((maxValue + 1) * Math.random());}return arr;}// for testpublic static int[] copyArray(int[] arr) {if (arr == null) {return null;}int[] res = new int[arr.length];for (int i = 0; i < arr.length; i++) {res[i] = arr[i];}return res;}// for testpublic static boolean isEqual(int[] arr1, int[] arr2) {if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {return false;}if (arr1 == null && arr2 == null) {return true;}if (arr1.length != arr2.length) {return false;}for (int i = 0; i < arr1.length; i++) {if (arr1[i] != arr2[i]) {return false;}}return true;}// for testpublic static void printArray(int[] arr) {if (arr == null) {return;}for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}// for testpublic static void main(String[] args) {int testTime = 500000;int maxSize = 100;int maxValue = 100000;boolean succeed = true;for (int i = 0; i < testTime; i++) {int[] arr1 = generateRandomArray(maxSize, maxValue);int[] arr2 = copyArray(arr1);radixSort(arr1);comparator(arr2);if (!isEqual(arr1, arr2)) {succeed = false;printArray(arr1);printArray(arr2);break;}}System.out.println(succeed ? "Nice!" : "Fucking fucked!");int[] arr = generateRandomArray(maxSize, maxValue);printArray(arr);radixSort(arr);printArray(arr);}}

穩定性

  • ?相同元素排序保證先后順序
  • 同樣數值的個體之間,如果不因為排序而改變相對次序,這個排序就是有穩定性的,否則則沒有
  • 基于比較的排序,一般都是不穩定的;基數排序(按照個位、十位、百位上的元素的大小進行相對次序的排列)和計數排序(統計相同數值的元素出現的次數,押入對應的元素組成的數據棧,利用棧先入后出的特性,保持元素的相對次序,參考上文統計0-200員工年齡分布問題)是穩定的
  • 不具備穩定性的排序:選擇排序、快速排序 和 堆排序
  • 具備穩定性的排序 :冒泡排序、插入排序 、歸并排序 、一切桶排序思想下的排序(計數排序和基數排序)
  • 目前沒有 時間復雜度為O(N*logN)? 額外時間復雜度O(1)? 又穩定的排序
  • 穩定性 主要體現在 非基礎類型數據的排序,比如對自定義結構體學生類型{年齡、班級},先按照年齡排序,再按照班級進行排序

分析

  • 桶排序思想下的排序都是不基于比較的排序
  • 時間復雜度為O(N),額外空間負載度O(M)
  • 應用范圍有限,需要樣本的數據狀況滿足桶的劃分

匯總

  • 快速排序不是基于比較的排序
?時間空間穩定性備注
選擇排序O(N^2)O(1)不穩定{5,5,5,3} 3和第一個5交換,不穩定
冒泡排序O(N^2)O(1)穩定?
插入排序O(N^2)O(1)穩定{3,4,4,5}新插入元素4,不可以越過與其相等元素的左邊,即元素相等的話,只會排在相等區域的最后位置
歸并排序O(N*logN)O(N)穩定{1,1,2,2}{1,1,2,2}左邊和右邊進行比較拼接的時候,先拷貝左邊的元素,再拷貝右邊的元素
快速排序O(N*logN)O(logN)不穩定{3,4,5,6,6,6,6,6,|2,333}? 2會和第一個6進行交換,打破了相對次序
堆排序O(N*logN)O(1)不穩定樹狀結構,{5,5,5,5,6}第一個5會和6交換,不穩定
桶排序(基數/計數)O(N)O(M)穩定非比較
  • 歸并、快排、和堆排序最為關鍵;不在乎穩定性的前提小,使用快速排序最好,時間最快(實驗可知);需要穩定性的話,使用歸并排序;在乎額外空間的話,使用堆排序

常見的坑

  • 歸并排序的額外空間復雜度可以變為O(1),但是會失去穩定性的優勢,詳見《歸并排序,內部緩沖法》
  • 原地歸并排序,很垃圾,會將時間復雜度變成O(N^2)
  • 快速排序也可以做到穩定性,但是非常難,詳見《01 stable sort》
  • 所有的改進都不重要? 目前沒有 時間復雜度為O(N*logN) 額外空間復雜度為? O(1) 又穩定的排序
  • 將一個數組中,所有的奇數移到數組的左邊,所有的偶數移到數組的右邊。保持相對次序不變的同時,要是時間復雜度為O(N),空間復雜度為O(1)。這個沒法做😂😂😂😂

對于排序的改進優化

  • 充分利用O(N*logN)和O(N^2)的排序的各自優勢
  • 數據規模很大的時候使用快速排序,當數據規模減少,數據項在60以內的時候,該換成插入排序,同時使用快速和插入兩種方法,能進一步提高效率,減少時間復雜度。

穩定性考慮

  • 如果輸入的數據是基礎類型,使用快速排序;如果輸入的類型是自定義的類型,使用插入、歸并這些可以保證穩定性的排序方法
  • Java里面自帶的排序算法,即array.sort,如果是常規類型,比如int的話是使用快速排序,提高速度;如果是自定義的類型,比如學生的年齡,結構體定義的字段,會使用桶排序,保證比較的穩定性。即算法看重時間復雜度 空間復雜度和穩定性(數值相等的元素排序,保證先后次序不變)
  • 基礎類型按照數值傳遞,非基礎類型,比如自定義結構體按照引用傳遞,具體體現在integer這個類型,127相等,128就不等了。因為128以上就作為不同內存了,也就是按照引用比較了

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

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

相關文章

RTP概述

1.1. RTP是什么 RTP全名是Real-time Transport Protocol&#xff08;實時傳輸協議&#xff09;。它是IETF提出的一個標準&#xff0c;對應的RFC文檔為RFC3550&#xff08;RFC1889為其過期版本&#xff09;。RFC3550不僅定義了RTP&#xff0c;而且定義了配套的相關協議RTCP&…

Java需要注意的一些小細節

更加精確的鎖定時間 判定納秒維度的時間 //使用System.nanoTime(); //例子 long start System.nanoTime(); long end System.nanoTime(); System.out.println(start); System.out.println(end);

live555的安裝 RTSP點播消息流程實例(客戶端:VLC, RTSP服務器:LIVE555 Media Server)

live555是一個開源的軟件&#xff0c;主要用來生成rtsp,rtp和sip服務器和客戶端的軟件。前幾天需要看一下vlc中的rtsp的功能&#xff0c;在vlc中rtp和rtsp的功能都是使用live555中的函數來生成的。該開源軟件的編譯&#xff0c;可以使用vc,mingw和cygwin等軟件。我安裝的時候使…

算法入門篇五 鏈表

牛客網 算法入門篇 判斷一個鏈表是否為回文結構 給定一個單鏈表的頭節點head&#xff0c;請判斷這個鏈表是否為回文結構1->2->1&#xff0c;返回為True;1->2->3為False 思路&#xff1a; 1&#xff0c;遍歷鏈表&#xff0c;將所有元素壓入棧中&#xff0c;然后再…

實時流媒體編程基于Linux環境開發

一、流媒體簡介 隨著Internet的日益普及&#xff0c;在網絡上傳輸的數據已經不再局限于文字和圖形&#xff0c;而是逐漸向聲音和視頻等多媒體格式過渡。目前在網絡上傳輸音頻/視頻&#xff08;Audio/Video&#xff0c;簡稱A/V&#xff09;等多媒體文件時&#xff0c;基本上只有…

算法入門篇六 二叉樹

牛客網 算法入門篇 左程云老師 個人復習&#xff0c;如果侵全&#xff0c;設為私密 二叉樹遍歷&#xff08;遞歸&#xff09; 先序遍歷&#xff08;中&#xff0c;左&#xff0c;右&#xff09; 中序遍歷&#xff08;左&#xff0c;中&#xff0c;右&#xff09; 后序遍歷&a…

VLC詳細的使用說明以及配置說明綜合示范實例精通VLC開發

vlc的全名是Video LanClient&#xff0c;是一個開源的、跨平臺的視頻播放器。VLC支持大量的音視頻傳輸、封裝和編碼格式&#xff0c;完整的功能特性列表可以在這里獲得http://www.videolan.org/vlc/features.html&#xff0c;下面給出一個簡要的不完整的列表&#xff1a;操作系…

算法入門篇七 前綴樹

牛客網 左程云老師的算法入門課 找二叉樹的節點的后繼節點 原則 如果節點有右子樹&#xff0c;那么后繼節點就是右子樹的最左邊的第一個節點如果節點沒有右子樹&#xff0c;如果節點是父節點的右孩子&#xff0c;就繼續往上找&#xff0c;直到找到一個父節點是沿途節點的父節…

VLC視頻播放器原理詳細分析含TS流格式分析

vlc是一個功能強大的玩意&#xff0c;能做很多有意思的事情。最簡單的&#xff0c;從界面打開一個文件播放&#xff0c;也可以在命令行下使用&#xff0c;如C:\Program Files\VideoLAN\VLC>vlc.exe test.ts獲取內置的幫助&#xff0c;會寫到vlc-help.txtC:\Program Files\Vi…

算法入門篇八 貪心算法

牛客網 左程云老師的算法入門課 貪心算法 貪心算法的解題步驟 例子 題目要求 解題策略 按照結束時間早的會議先安排&#xff0c;比如先安排【2&#xff0c;4】&#xff0c;當4結束了&#xff0c;所有開始時間小于4的全部淘汰&#xff0c;【1&#xff0c;7】、【3&#xff…

算法入門篇九 暴力遞歸

牛客網 左程云老師的算法入門課 暴力遞歸 原則 漢諾塔問題 問題 打印n層漢諾塔從左邊移動到最右邊的過程 思想 一共六個過程&#xff0c;左到右、左到中&#xff0c;中到左&#xff0c;中到右&#xff0c;右到左&#xff0c;右到中&#xff0c;互相嵌套使用 左到右 將1…

rtsp和sdp

RTSP 是由Realnetwork 和Netscape共同提出的如何有效地在IP網絡上傳輸流媒體數據的應用層協議 。 實時流協議&#xff08;RTSP&#xff09;建立并控制一個或幾個時間同步的連續流媒體&#xff0c;如音頻和視頻。盡管連續媒體流與控制流交叉是可能的&#xff0c;RTSP本身并不發…

使用javascript實現對于chineseocr的API調用

ChineseOCR在線API 網頁地址 界面 提供多種接口調用方式&#xff0c;比如在線調用、Javascript api調用、curl api調用和python api調用四種方式&#xff0c;本次使用javascript api調用的方式進行OCR識別在線Javascript工具 在線工具網頁鏈接在線Base64 轉化工具 在線工具…

移動流媒體業務的技術與標準

1 引言   流媒體業務是從Internet上發展起來的一種多媒體應用&#xff0c;指使用流&#xff08;Streaming&#xff09;方式在網絡上傳輸的多媒體文件&#xff0c;包括音頻、視頻和動畫等。   流媒體傳輸技術的主要特點是以流&#xff08;streaming&#xff09;的形式進行多…

使用python實現對于chineseocr的API調用

ChineseOCR在線API 網頁鏈接 界面 提供多種接口調用方式&#xff0c;比如在線調用、Javascript api調用、curl api調用和python api調用四種方式&#xff0c;本次使用javascript api調用的方式進行OCR識別在線Base64 轉化工具 Base64在線小工具代碼修改 新增一個變量fill_w…

UDP穿透NAT

NAT(Network AddressTranslators)&#xff0c;網絡地址轉換&#xff1a; 網絡地址轉換是在IP地址日益缺乏的情況下產生的&#xff0c;它的主要目的就是為了能夠地址重用。NAT分為兩大類&#xff0c;基本的NAT和NAPT(Network Address/Port Translator)。 最開始NAT是運行在路由器…

算法入門篇十 圖

圖的存儲方式 臨接表臨接矩陣 表達 點集/邊集有向圖/無向圖 Graph&#xff08;大結構就是圖&#xff09;&#xff08;包含點集合和邊集合&#xff09; import java.util.HashMap; import java.util.HashSet;public class Graph {public HashMap<Integer, Node> nodes;…

SDP協議 學習筆記

SDP:Session Description ProtocolSDP格式:Session descriptionv (protocolversion)o (owner/creatorand session identifier)s (sessionname)i* (sessioninformation)u* (URI ofdescription)e* (emailaddress)p* (phonenumber)c*(connection information - not required if in…

以太坊私有鏈 使用dev模式

dev 使用dev模式&#xff0c;創建一個管理員賬號&#xff0c;控制挖礦&#xff0c;將證明機制改為POA啟動dev模式&#xff0c;需要重新創建一個文件夾&#xff0c;重新搭建私有鏈條 命令 mkdir myDevChain cd myDevChain geth --datadir . --dev console 2>output.log 實…

超文本傳輸協議

超文本傳輸協議 超文本傳輸協議超文件傳輸協定(HTTP&#xff0c;HyperTextTransfer Protocol)是因特網上應用最為廣泛的一種網絡傳輸協定。所有的WWW文件都必須遵守這個標準。設計HTTP最初的目的是為了提供一種發布和接收HTML頁面的方法。 目錄 介紹請求信息請求方法安全方法超…