排序演算法—歸併排序的Java實現,效率比選擇排序要低?
初級Java開發人員面試,經常會碰到技術面試官問排序演算法,幾乎每次面試一遍都要刷一遍排序演算法……,今天正在刷歸併排序,居然發現在100000級別的資料量中歸併演算法的執行時間居然比選擇排序要長,百思不得解,最後在比較多位大神blog中的程式碼實現,發現問題的根源,在此做一個記錄,也算是一個成長道路上的積累吧。
歸併排序演算法的實現步驟(網上貼的)
* 把長度為n的輸入序列分成兩個長度為n/2的子序列;
* 對這兩個子序列分別採用歸併排序;
* 將兩個排序好的子序列合併成一個最終的排序序列。
選擇排序演算法實現:
/**
* 它的工作原理很容易理解: 1.初始時在序列中找到最小(大)元素,放到序列的起始位置作為已排序序列;
* 2.然後,再從剩餘未排序元素中繼續尋找最小(大)元素,放到已排序序列的末尾; 3.以此類推,直到所有元素均排序完畢。
*
* @return int[]
* @Author Administrator
* @Date 2018年3月7日
*/
public static void selectSort(int arr[]) {
long start = System.currentTimeMillis();
if (arr != null && arr.length > 1) {
for (int i = 0; i < arr.length - 1; i++) {
int min = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[min] > arr[j]) {
min = j;
}
}
if (min != i) {
swap(arr, i, min);
}
}
}
System.out.println("select sort 耗時 : " + (System.currentTimeMillis() - start) + "ms");
}
第一版歸併演算法實現:
/**
* 歸併排序
* 把長度為n的輸入序列分成兩個長度為n/2的子序列;
* 對這兩個子序列分別採用歸併排序;
* 將兩個排序好的子序列合併成一個最終的排序序列。
* @param arr
*/
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 1) {
return;
}
long start = System.currentTimeMillis();
doMergeSort(arr, 0, arr.length-1);
System.out.println("merge sort 耗時 : " + (System.currentTimeMillis() - start) + "ms");
}
private static void doMergeSort(int[] arr, int start, int end) {
if (start >=end) {
return;
}
int mid = (start + end) >>1;
doMergeSort(arr, start, mid);
doMergeSort(arr, mid+1, end);
merge(arr, start,mid, end);
}
/**
*合併子序列
*
* @param arr
* @param start
* @param end
*/
private static void merge(int[] arr, int start,int mid, int end) { *//注意此處,產生臨時資料表,儲存已經歸併了的子序列
*int[] temp = new int[arr.length];*
int tp=start,lp=start,rp=mid +1;
while(lp<=mid&&rp<=end){
if(arr[lp]<=arr[rp]){
temp[tp++] =arr[lp++] ;
}else{
temp[tp++] =arr[rp++] ;
}
}
while(lp<=mid){
temp[tp++] =arr[lp++] ;
}
while(rp<=end){
temp[tp++] =arr[rp++] ;
}
int cp =start;
//從臨時陣列拷貝到原陣列
while(cp<=end){
arr[cp] = temp[cp];
cp++;
}
}
執行結果比較:
資料量:10000
select sort 耗時 : 62ms
merge sort 耗時 : 112ms
歸併排序耗時近乎選擇排序耗時兩倍。
改良後的程式碼實現:
/**
* 歸併排序 把長度為n的輸入序列分成兩個長度為n/2的子序列;
* 對這兩個子序列分別採用歸併排序;
* 將兩個排序好的子序列合併成一個最終的排序序列。
*
* @param arr
*/
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 1) {
return;
}
long start = System.currentTimeMillis();
int[] temp = new int[arr.length];
doMergeSort(arr, 0, arr.length - 1,temp);
System.out.println("merge sort 耗時 : " + (System.currentTimeMillis() - start) + "ms");
}
private static void doMergeSort(int[] arr, int start, int end,int[] temp) {
if (start >= end) {
return;
}
int mid = (start + end) >> 1;
doMergeSort(arr, start, mid,temp);
doMergeSort(arr, mid + 1, end,temp);
merge(arr, start, mid, end,temp);
}
/**
* 合併子序列
*
* @param arr
* @param start
* @param end
*/
private static void merge(int[] arr, int start, int mid, int end,int[] temp) {
// 此處new temp降低排序效能
int tp = start, lp = start, rp = mid + 1;
while (lp <= mid && rp <= end) {
if (arr[lp] <= arr[rp]) {
temp[tp++] = arr[lp++];
} else {
temp[tp++] = arr[rp++];
}
}
while (lp <= mid) {
temp[tp++] = arr[lp++];
}
while (rp <= end) {
temp[tp++] = arr[rp++];
}
int cp = start;
// 從臨時陣列拷貝到原陣列
while (cp <= end) {
arr[cp] = temp[cp];
cp++;
}
}
效率比較:
select sort 耗時 : 71ms
merge sort 耗時 : 6ms
效率得到飛一般的提升,那麼兩種實現的為何會相差這麼多呢?
我的分析是在資料量大的時候,執行merge方法的次數必然增多,每呼叫merge方法,執行一次int[] temp = new int[arr.length];產生一個臨時物件,降低了效能。改良後的實現,在外部呼叫merge時把臨時資料表當做引用傳入方法中,在整個排序過程中始終始終只需要一個額外的臨時空間,因此效率得到大幅度上升。
網上有些Blog貼出的第一版的實現,再次我引以為鑑,踩過坑才能不入坑!
相關推薦
排序演算法—歸併排序的Java實現,效率比選擇排序要低?
初級Java開發人員面試,經常會碰到技術面試官問排序演算法,幾乎每次面試一遍都要刷一遍排序演算法……,今天正在刷歸併排序,居然發現在100000級別的資料量中歸併演算法的執行時間居然比選擇排序要長,百思不得解,最後在比較多位大神blog中的程式碼實現,發現問題的
PAT乙級——1035(插入排序和歸併)java實現
題目: 插入與歸併 (25 分) 根據維基百科的定義: 插入排序是迭代演算法,逐一獲得輸入資料,逐步產生有序的輸出序列。每步迭代中,演算法從輸入序列中取出一元素,將之插入有序序列中正確的位置。如此迭代直到全部元素有序。 歸併排序進行如下迭代操作:首先將原始序列看成
簡單選擇排序演算法原理及java實現(超詳細)
選擇排序是一種非常簡單的排序演算法,就是在序列中依次選擇最大(或者最小)的數,並將其放到待排序的數列的起始位置。 簡單選擇排序的原理 簡單選擇排序的原理非常簡單,即在待排序的數列中尋找最大(或者最小)的一個數,與第 1 個元素進行交換,接著在剩餘的待排序的數列中繼續找最大(最小)的一個數,與第 2 個元素交
這可能是最透徹的氣泡排序演算法解析(java實現)
氣泡排序是一種思想簡單,便於理解和實現的排序演算法,也許是很多人學習的第一個排序演算法,廢話不多說,我們來實現它 演算法詳解 我們以升序排列為例,演算法的思想是,遍歷整個陣列,依次對陣列中的每兩個數進行比較大小,通過兩個數字的交換,達到將最大的元素移動到陣列的最
常用排序演算法總結(Java實現)
排序演算法比較: 1. 氣泡排序 /** * 氣泡排序 * 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。 * 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。 * 針對所有的元素重複以上的步驟,除了最後一個
插入排序演算法思路及Java實現
1.插入排序演算法思路 我們首先來看看插入排序的過程: 2.插入排序虛擬碼實現 3.插入排序java程式碼實現 public class InsertionSort { public static void main(String[] args) {
時間複雜度為O(N*logN)的常用排序演算法總結與Java實現
時間複雜度為O(N*logN)的常用排序演算法主要有四個——快速排序、歸併排序、堆排序、希爾排序1.快速排序·基本思想 隨機的在待排序陣列arr中選取一個元素作為標記記為arr[index](有時也直接選擇起始位置),然後在arr中從後至前以下標j尋找比arr[inde
八大排序演算法總結與Java實現
概述 因為健忘,加上對各種排序演算法理解不深刻,過段時間面對排序就蒙了。所以決定對我們常見的這幾種排序演算法進行統一總結,強行學習。首先羅列一下常見的十大排序演算法: 直接插入排序 希爾排序 簡單選擇排序 堆排序 氣泡排
九種排序演算法總結與Java實現
一、九種排序演算法總結 平均時間複雜度O(n^2): 氣泡排序、選擇排序、插入排序 平均時間複雜度O(nln): 快速排序、歸併排序、堆排序 時間複雜度介於O(nlgn)和O(n^2):希爾排序 時間複雜度O(n+k):計數排序 時間複雜度O(d(n+k)):基數排序
八種排序演算法總結(Java實現)
排序演算法有很多,在特定情景中使用哪一種演算法很重要。本文對幾種常見排序演算法做了簡單的總結。 一、氣泡排序 氣泡排序(BubbleSort)是一種簡單的排序演算法。它重複地走訪要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交
堆排序演算法思路以及Java實現
這幾天忙著找工作,看到有去阿里面試的同學遇到了堆排序的問題,因此就去網上看部落格學習,但看半天實在看不懂,只好把演算法導論拿出來啃,沒想到還挺簡單,所以在這裡分享給大家。 0.堆簡介 堆(二叉堆)可以視為一棵完全的二叉樹,完全二叉樹的一個“優秀”的性質是,除了最底層之外,
(排序演算法)linux c語言實現簡化版本的插入排序演算法(二分插入)
二分插入演算法是在已經排序好的序列裡插入一個元素,是穩定的演算法,關鍵詞是折中。 比如說我要在12345678910裡插入一個3,那麼我先看看中間的數比3大,還是比3小,要是比3大,我就去後一半,如果是比3小,我就去前一半,現在進入某個一半後,再做如此操作,最後將其他的元
常見的三種排序演算法分析及對比實現(冒泡、選擇、插入)
1. 氣泡排序 1)基本思想: 在要排序的一組數中,對當前還未排好序的範圍內的全部數,自上而下對相鄰的兩個數依次進行比較和調整, 讓較大的數往下沉,較小的往上冒。即:每當兩相鄰的數比較後發現它們的排序與排序要求相反時,就
分散式系統應用中生成全域性唯一ID的演算法(snowflake)----java 實現,單例模式
概述 在分散式系統中,有很多的地方需要生成全域性id的場景,比方說,訂單模組,使用者id等。這種情況下大多數的做法是通過UUID來做處理。首先,UUID是36位的一個字串,相對來說是比較長的,一般我們採用的資料庫會是MySQL,因為大多數的情況下,我們都希望我們的資料是可以
買什麼資料結構與演算法,這裡有:動態圖解十大經典排序演算法(含JAVA程式碼實現)
上篇的動圖資料結構反響不錯,這次來個動圖排序演算法大全。資料結構與演算法,齊了。 幾張動態圖捋清Java常用資料結構及其設計原理 本文將採取動態圖+文字描述+正確的java程式碼實現來講解以下十大排序演算法: 氣泡排序 選擇排序 插入排序 希爾排序
[排序演算法]--歸併排序的Java實現
歸併排序(2-路歸併):歸併排序是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用,歸併排序將兩個已排序的表合併成一個表。 下面先看一個歸併排序過程的示例: 待排序列(14,12
基礎排序演算法 java 實現(冒泡、選擇、插入、快排、歸併、堆排)
package demo; import java.util.Arrays; public class SortUtil { private static void printArr(int[] arr) { System.out.println
設計一個包含一個interface,三個class的Java 程式,用於完成陣列排序排序任務。其中interface中包含一個sort() 方法。第一個class使用氣泡排序法實現interface的
題目:設計一個包含一個interface,三個class的Java 程式,用於完成陣列排序排序任務。其中interface中包含一個sort() 方法。第一個class使用氣泡排序法實現interface的sort()方法;第二個class使用選擇排序法實現interface的sort()方法;
常見排序演算法記錄(基於java語言實現)
桶排序 public class TongPaiXu1 { public static void main(String[] args) { // 桶排序 int[] m = {1, 3, 6, 3, 4,
【資料結構與演算法】之排序全家桶(十大排序詳解及其Java實現)---第七篇
本篇文章彙總了10種場常見的排序演算法,篇幅較長,可以通過下面的索引目錄進行定位查閱: 7、桶排序 一、排序的基本概念 1、排序的定義 排序:就是使一串記錄,按照其中的某個或者某些關鍵字的大小,遞增或遞減的排列起來