基礎不牢地動山搖記住 Java 面試中常用的八種排序算法與代碼實現

2020-12-23 酷扯兒

本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫

1.直接插入排序

經常碰到這樣一類排序問題:把新的數據插入到已經排好的數據列中。

將第一個數和第二個數排序,然後構成一個有序序列將第三個數插入進去,構成一個新的有序序列。對第四個數、第五個數……直到最後一個數,重複第二步。

如何寫成代碼:

首先設定插入次數,即循環次數,for(int i=1;i<length;i++),1個數的那次不用插入。< span>設定插入數和得到已經排好序列的最後一個數的位數。insertNum和j=i-1。從最後一個數開始向前循環,如果插入數小於當前數,就將當前數向後移動一位。將當前數放置到空著的位置,即j+1。代碼實現如下:

public void insertSort(int[] a){int length=a.length;//數組長度,將這個提取出來是為了提高速度。 int insertNum;//要插入的數 for(int i=1;i<length;i++){//插入的次數 insertNum=a[i];//要插入的數 int j=i-1;//已經排序好的序列元素個數 while(j>=0&&a[j]>insertNum){//序列從後到前循環,將大於insertNum的數向後移動一格 a[j+1]=a[j];//元素移動一格 j--; } a[j+1]=insertNum;//將需要插入的數放在要插入的位置。 } }

2.希爾排序

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

將數的個數設為n,取奇數k=n/2,將下標差值為k的數分為一組,構成有序序列。再取k=k/2 ,將下標差值為k的書分為一組,構成有序序列。重複第二步,直到k=1執行簡單插入排序。

如何寫成代碼:

首先確定分的組數。然後對組中元素進行插入排序。然後將length/2,重複1,2步,直到length=0為止。代碼實現如下:

public void sheelSort(int[] a){int d = a.length; while (d!=0) { d=d/2; for (int x = 0; x < d; x++) {//分的組數 for (int i = x + d; i < a.length; i += d) {//組中的元素,從第二個數開始 int j = i - d;//j為有序序列最後一位的位數 int temp = a[i];//要插入的元素 for (; j >= 0 && temp < a[j]; j -= d) {//從後往前遍歷。 a[j + d] = a[j];//向後移動d位 } a[j + d] = temp; } } } }

3.簡單選擇排序

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

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

遍歷整個序列,將最小的數放在最前面。遍歷剩下的序列,將最小的數放在最前面。重複第二步,直到只剩下一個數。

如何寫成代碼:

首先確定循環次數,並且記住當前數字和當前位置。將當前位置後面所有的數與當前數字進行對比,小數賦值給key,並記住小數的位置。比對完成後,將最小的值與第一個數的值交換。重複2、3步。代碼實現如下:

public void selectSort(int[] a) { int length = a.length; for (int i = 0; i < length; i++) {//循環次數 int key = a[i]; int position=i; for (int j = i + 1; j < length; j++) {//選出最小的值和位置 if (a[j] < key) { key = a[j]; position = j; } } a[position]=a[i];//交換位置 a[i]=key; } }

4.堆排序

對簡單選擇排序的優化。

將序列構建成大頂堆。將根節點與最後一個節點交換,然後斷開最後一個節點。重複第一、二步,直到所有節點斷開。

代碼實現如下:

public void heapSort(int[] a){System.out.println("開始排序"); int arrayLength=a.length; //循環建堆 for(int i=0;i<arraylength-1;i++){ //建堆 buildMaxHeap(a,arrayLength-1-i); //交換堆頂和最後一個元素 swap(a,0,arrayLength-1-i); System.out.println(Arrays.toString(a)); } } private void swap(int[] data, int i, int j) { // TODO Auto-generated method stub int tmp=data[i]; data[i]=data[j]; data[j]=tmp; } //對data數組從0到lastIndex建大頂堆 private void buildMaxHeap(int[] data, int lastIndex) { // TODO Auto-generated method stub //從lastIndex處節點(最後一個節點)的父節點開始 for(int i=(lastIndex-1)/2;i>=0;i--){ //k保存正在判斷的節點 int k=i; //如果當前k節點的子節點存在 while(k*2+1<=lastIndex){ //k節點的左子節點的索引 int biggerIndex=2*k+1; //如果biggerIndex小於lastIndex,即biggerIndex+1代表的k節點的右子節點存在 if(biggerIndex<lastindex){ //若果右子節點的值較大 if(data[biggerIndex]<data[biggerindex+1]){ //biggerIndex總是記錄較大子節點的索引 biggerIndex++; } } //如果k節點的值小於其較大的子節點的值 if(data[k]<data[biggerindex]){ //交換他們 swap(data,k,biggerIndex); //將biggerIndex賦予k,開始while循環的下一次循環,重新保證k節點的值大於其左右子節點的值 k=biggerIndex; }else{ break; } } } }

5.冒泡排序

一般不用。

將序列中所有元素兩兩比較,將最大的放在最後面。將剩餘序列中所有元素兩兩比較,將最大的放在最後面。重複第二步,直到只剩下一個數。

如何寫成代碼:

設置循環次數。設置開始比較的位數,和結束的位數。兩兩比較,將最小的放到前面去。重複2、3步,直到循環次數完畢。代碼實現如下:

public void bubbleSort(int[] a){int length=a.length; int temp; for(int i=0;i<a.length;i++){ for(int j=0;j<a.length-i-1;j++){ if(a[j]>a[j+1]){ temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } } }

6.快速排序

要求時間最快時。

選擇第一個數為p,小於p的數放在左邊,大於p的數放在右邊。遞歸的將p左邊和右邊的數都按照第一步進行,直到不能遞歸。

代碼實現如下:

public static void quickSort(int[] numbers, int start, int end) { if (start < end) { int base = numbers[start]; // 選定的基準值(第一個數值作為基準值) int temp; // 記錄臨時中間值 int i = start, j = end; do { while ((numbers[i] < base) && (i < end)) i++; while ((numbers[j] > base) && (j > start)) j--; if (i <= j) { temp = numbers[i]; numbers[i] = numbers[j]; numbers[j] = temp; i++; j--; } } while (i <= j); if (start < j) quickSort(numbers, start, j); if (end > i) quickSort(numbers, i, end); } }

7.歸併排序

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

選擇相鄰兩個數組成一個有序序列。選擇相鄰的兩個有序序列組成一個有序序列。重複第二步,直到全部組成一個有序序列。

代碼實現如下:

public static void mergeSort(int[] numbers, int left, int right) { int t = 1;// 每組元素個數 int size = right - left + 1; while (t < size) { int s = t;// 本次循環每組元素個數 t = 2 * s; int i = left; while (i + (t - 1) < size) { merge(numbers, i, i + (s - 1), i + (t - 1)); i += t; } if (i + (s - 1) < right) merge(numbers, i, i + (s - 1), right); } } private static void merge(int[] data, int p, int q, int r) { int[] B = new int[data.length]; int s = p; int t = q + 1; int k = p; while (s <= q && t <= r) { if (data[s] <= data[t]) { B[k] = data[s]; s++; } else { B[k] = data[t]; t++; } k++; } if (s == q + 1) B[k++] = data[t++]; else B[k++] = data[s++]; for (int i = p; i <= r; i++) data[i] = B[i]; }

8.基數排序

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

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

代碼實現如下:

public void sort(int[] array) {//首先確定排序的趟數; int max = array[0]; for (int i = 1; i < array.length; i++) { if (array[i] > max) { max = array[i]; } } int time = 0; //判斷位數; while (max > 0) { max /= 10; time++; } //建立10個隊列; List queue = new ArrayList(); for (int i = 0; i < 10; i++) { ArrayList queue1 = new ArrayList(); queue.add(queue1); } //進行time次分配和收集; for (int i = 0; i < time; i++) { //分配數組元素; for (int j = 0; j < array.length; j++) { //得到數字的第time+1位數; int x = array[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i); ArrayList queue2 = queue.get(x); queue2.add(array[j]); queue.set(x, queue2); } int count = 0;//元素計數器; //收集隊列元素; for (int k = 0; k < 10; k++) { while (queue.get(k).size() > 0) { ArrayList queue3 = queue.get(k); array[count] = queue3.get(0); queue3.remove(0); count++; } } } }

相關焦點

  • Java實現冒泡排序算法
    學習方法推薦:#學習方法1.從基礎開始,系統化學習2.多動手,每一種數據結構與算法,都自己用代碼實現出來3.思路更重要:理解實現思想,不要背代碼4.與日常開發結合,對應應用場景>2.考考你在上一篇:數據結構與算法系列十(排序概述)中,我們列舉了常用的排序算法,以及分析了如何綜合衡量排序算法的優劣。
  • 數據結構與算法:聊一聊在面試中被常問的那幾個基礎算法的理解
    前面我也說到:數據結構和算法是一對"相愛相殺的"組合,所以接下來要分享下我個人對於一些算法的理解和實現。本文將主要分享基礎的查找和排序(代碼基於python)既然要開始分享算法,那必然要先介紹下算法相關的一些基本術語,如下。
  • 經典排序算法五 堆排序(JAVA實現)
    堆排序基本原理堆排序是利用堆這種數據結構而設計的一種排序算法,堆排序是一種選擇排序。首先我們來了解下什麼是堆。堆分為兩種:大頂堆和小頂堆,兩者的差別主要在於排序方式。堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。
  • Java基礎面試題簡單總結
    Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各種集合的搜索、排序、線程安全化等操作6、什麼時候用assert答:assertion(斷言)在軟體開發中是一種常用的調試方式,很多開發語言中都支持這種機制。
  • 憑藉清華掃地僧的路線指引,從Java基礎到算法,吊打阿里面試官!
    字節跳動面試總共是3+1面試(技術3面+HR1面),三面技術具體問了什麼題目我是有點分不清了,不過我記得每個知識點大概問了那些問題,大致就是分為Java架構基礎+Redis+Linux/作業系統+HTTPS+MySQL資料庫+算法這六個部分吧,不過話說回來,這次之所以能僥倖過關,多虧了清華掃地僧大佬的學習路線,自己也下了大功夫,也算是功夫不負有心人吧~~~
  • JavaScript實現排序算法
    如4N^2^,大O表示法表示為:O(N^2^);二、排序算法這裡主要介紹幾種簡單排序和高級排序:簡單排序:冒泡排序、選擇排序、插入排序;高級排序:>以下代碼實現中採用希爾排序原稿中建議的增量即N / 2。
  • 程式設計師必備的幾種常見排序算法和搜索算法總結
    .在真實項目中我們往往不會採用冒泡排序,更多的會用快速排序或者希爾排序.關於排序算法性能問題我在《前端算法系列》如何讓前端代碼速度提高60倍有詳細介紹.接下來就讓我們來一起學習如何實現文章開頭的幾個常用排序和搜索算法吧.1. 冒泡排序及其優化我們在學排序算法時, 最容易掌握的就是冒泡排序, 因為其實現起來非常簡單,但是從運行性能的角度來看, 它卻是性能最差的一個.
  • 排序算法:歸併排序
    在日常開發中經常會遇到一類問題,就是對一個集合的數據進行排序掌握一些排序算法,對於日常開發是非常有幫助今天介紹一下歸併排序法01算法邏輯02時間複雜度由上圖邏輯可以得出,歸併排序的循環次數為由算法導論的主定理可以推導出,可見之前的文章(文末有連結)歸併排序的時間複雜度為03空間複雜度由上圖邏輯可以得出,歸併排序每次分解都是要復一份新的數據片段
  • 五大常用算法:一文搞懂分治算法
    原創公眾號:bigsai文章收錄在 bigsai-algorithm前言分治算法(divide and conquer)是五大常用算法(分治算法、動態規划算法、貪心算法、回溯法、分治界限法)之一,很多人在平時學習中可能只是知道分治算法,但是可能並沒有系統的學習分治算法
  • 輕鬆搞定,Java選擇排序算法
    前言不知不覺,今年已經大半年 時間就過去了,很多公司秋招已經開始了,然後數據結構 與算法就是公司常拿來考察同學們的基礎,今天我們一起來學習Java中最簡單的算法,叫選擇排序算法。正文選擇排序算法,是一種簡單直觀的排序算法,它的思路是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的數據元素排完。但是注意選擇排序它是不穩定的排序方法的。
  • 用Python實現常見的四種排序算法
    排序是每個軟體工程師和開發人員都需要掌握的技能。不僅要通過編程面試,還要對程序本身有一個全面的理解。不同的排序算法很好地展示了算法設計上如何強烈的影響程序的複雜度、運行速度和效率。排序有很多種實現方法,比如冒泡排序、選擇排序、歸併排序、希爾排序、快速排序、插入排序、堆排序、基數排序等,今天就給大家介紹使用Python語言實現的其中4個排序算法。1. 快速排序首先要打亂序列順序 ,以防算法陷入最壞時間複雜度。快速排序使用「分而治之」的方法。
  • java內存溢出問題(工作中常用、面試中常問的一個知識點)
    內存溢出是指應用系統中存在無法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大於虛擬機能提供的最大內存。這篇文章整理自《深入理解java虛擬機》。因為內存溢出問題不僅是工作中的一個重要方面,而且面試中也是經常問。
  • 堆排序原理及實現
    經常聽到研發麵試基礎題或者說基本功都包括算法題目
  • 給Java新手的一些建議——Java知識點歸納(Java基礎部分)
    JVM作為java運行的基礎,很難相信對於JVM一點都不了解的人可以把java語言吃得很透。我在面試有超過3年Java經驗的開發者的時候, JVM幾乎就是一個必問的問題了。當然JVM不是唯一決定技術能力好壞的面試問題,但是可以佐證java開發能力的高低。
  • java從菜鳥到大神學習路線:高級篇,最全系列教程!
    教程學習群:(群號見下方圖片),裡面都是學習java的,如果你想製作酷炫的網頁,想學習java知識,小編歡迎你的加入。小編會在群中不定期分享乾貨源碼,包括我精心整理的一份java零基礎教程。歡迎各位感興趣的的小夥伴。
  • 視覺直觀感受 7 種常用的排序算法
    事實上,快速排序通常明顯比其他Ο(n log n) 算法更快,因為它的內部循環(inner loop)可以在大部分的架構上很有效率地被實現出來,且在大部分真實世界的數據,可以決定設計的選擇,減少所需時間的二次方項之可能性。
  • 零基礎java入門教程function函數應用菜鳥與大師僅一個代碼的差距
    菜鳥與大師差距的神話當我們在編寫程序,其實就是在不斷的實現功能,而java當中最小的功能單元就是函數,所以日後在代碼的時,只要在處理或者定義功能時,都把它定義到獨立的函數當中,而不要在把代碼都亂七八糟的定義到主函數當中去了
  • 拓撲排序算法及C語言實現
    圖 1 有向無環圖例如,圖 1 中的兩個圖都是有向無環圖,都可以使用拓撲排序對圖中的頂點進行排序,兩個圖形的區別是:左圖中的 V2 和 V3 之間沒有明確的前後順序;而右圖中任意兩個頂點之間都有前後順序。左圖中頂點之間的關係被稱為「偏序」關係;右圖中頂點之間的關係被稱為」全序「關係。
  • 2020學習Java必看的3本書籍
    《Effective Java》本書一共包含90個條目,每個條目討論Java程序設計中的一條規則。這些規則反映了最有經驗的優秀程式設計師在實踐中常用的一些有益的做法。本書的目標是幫助讀者更加有效地使用Java程式語言及其基本類庫:java.lang、java.util和java.io,以及子包,如java.util.concurrent和java.util.function。本書時不時地也會討論其他的類庫。3.
  • 年初離職,學習半年源碼,終於拿到了螞蟻Offer,分享面試過程
    小夥伴從去年開始,一直叨叨要跳槽,大大小小的公司面試了很多,但總沒有拿到一個滿意的offer,要麼package太低,要麼就是面試被虐。經過前幾次的面試失利,終於明白了什麼叫基礎不牢,地動山搖。面試官隨便針對一個知識點深入考察一下,就回答不出來,就這樣,還怎麼能通過面試?不過,最近收到了小夥伴的捷報,已拿到阿里的offer,公司足夠大,base還可以,雖然是個P6,但還是隱隱感覺到他很滿意。其實,我還是有點疑惑,他之前的基礎很一般,咋就突然拿到了阿里的offer。