1. 程式人生 > >九種基本排序演算法總結

九種基本排序演算法總結

排序分類: 1、插入排序:直接插入排序,二分法插入排序,希爾排序; 2、選擇排序:簡單選擇排序,堆排序; 3、交換排序:氣泡排序,快速排序; 4、歸併排序;

5、基數排序;

(1)直接插入排序:(穩定排序)     基本思想:將每個待排序的記錄,按照其順序碼的大小插入到前面已經排序好的子序列的合適位置(從後向前找合適位置),直到全部插入排序完成為止。     時間複雜度:平均時間複雜度為O(n^2)。 檔案初態不同時,直接插入排序所耗費的時間有很大差異。若檔案初態為正序,則每個待插入的記錄只需要比較一次就能夠找到合適的位置插入,故演算法的時間複雜度為O(n),這時最好的情況。若初態為反序,則第i個待插入記錄需要比較i+1次才能找到合適位置插入,故時間複雜度為O(n^2),這時最壞的情況。
/*
  * 直接插入排序
  */
 static void directInsertSort(int []array){
  int i,j,temp;
        for (i = 1; i < array.length; i++) {
            //待插入元素
            temp = array[i];
            for (j = i-1; j>=0 && array[j]>temp; j--) {
                //將大於temp的往後移動一位
             array[j+1] = array[j];
            }
            array[j+1] = temp;
        }
 }
(2)二分法插入排序(穩定排序) 基本思路:同直接插入排序,只是尋找插入位置的方法不同,使用二分法確定插入位置; 時間複雜度:平均時間複雜度為O(n^2)。
/*
  * 二分插入排序
  */
 static void binaryInsertSort(int []array){
  int left,right,mid,temp;
  for(int i=0;i<array.length;i++)
  {
   temp=array[i];
   left=0;
   right=i-1;
   mid=0;
   while(left<=right){
    mid=(left+right)/2;
    if(temp<array[mid])
     right=mid-1;
    else {
     left = mid+1;
    }
   }
   for(int j=i-1;j>=left;j--){
    array[j+1]=array[j];
   }
   array[left]=temp;
  }
 }
(3)希爾排序(不穩定排序)     基本思路:先取一個小於n的整數d1作為第一個增量,把檔案的全部記錄分成d1個組。所有距離為d1的倍數的記錄放在同一個組中。先在各組內進行直接插入排序;然後,取第二個增量d2<d1重複上述的分組和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有記錄放在同一組中進行直接插入排序為止。該方法實質上是一種分組插入方法。
    時間複雜度:平均時間複雜度為O(nlogn)

    希爾排序的時間效能優於直接插入排序,原因如下:

  (1)當檔案初態基本有序時直接插入排序所需的比較和移動次數均較少。   (2)當n值較小時,n和n2的差別也較小,即直接插入排序的最好時間複雜度O(n)和最壞時間複雜度0(n2)差別不大。   (3)在希爾排序開始時增量較大,分組較多,每組的記錄數目少,故各組內直接插入較快,後來增量di逐漸縮小,分組數逐漸減少,而各組的記錄數目逐漸增多,但由於已經按di-1作為距離排過序,使檔案較接近於有序狀態,所以新的一趟排序過程也較快。   因此,希爾排序在效率上較直接插人排序有較大的改進。
/*
  * 希爾排序
  */
 static void xierInsertSort(int []array){
  int interval=array.length;
  while(true){
   interval=interval/2;
   for(int i=0;i<array.length;i++){
    directInsertSort(array,i,interval);
   }
   if(interval==1)
    break;
  }
 
 }
  /*
  * 直接插入排序
  */
 static void directInsertSort(int []array,int start,int interval){
  int i,j,temp;
        for (i = start; i < array.length; i=i+interval) {
            //待插入元素
            temp = array[i];
            for (j = i-interval; j>=0 && array[j]>temp; j=j-interval) {
                //將大於temp的往後移動interval
             array[j+interval] = array[j];
            }
            array[j+interval] = temp;
        }
 }

(4)直接選擇排序(不穩定排序)     基本思路:在要排序的一組數中,選出最小的一個數與第一個位置的數交換;然後在剩下的數當中再找最小的與第二個位置的數交換,如此迴圈到倒數第二個數和最後一個數比較為止。     時間複雜度:平均時間複雜度為O(n^2)。
  /*
  * 簡單選擇排序
  */
 static void simpleSelectSort(int []array){
  int i,j,temp,flag;
        for (i = 0; i < array.length; i++) {
            temp = array[i];
            flag=i;
            for (j = i+1; j<array.length; j++) {
                if(array[j]<temp){
                 temp=array[j];
                 flag=j;
                }
            }
            array[flag]=array[i];
            array[i] = temp;
        }
 }

(5)堆排序(不穩定排序)     堆的定義下:具有n個元素的序列 (h1,h2,...,hn),當且僅當滿足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,...,n/2)時稱之為堆。     基本思路:初始時把要排序的數的序列看作是一棵順序儲存的二叉樹,調整它們的儲存序,使之成為一個堆,這時堆的根節點的數最大。然後將根節點與堆的最後一個節點交換。然後對前面(n-1)個數重新調整使之成為堆。依此類推,直到只有兩個節點的堆,並對它們作交換,最後得到有n個節點的有序序列。從演算法描述來看,堆排序需要兩個過程,一是建立堆,二是堆頂與堆的最後一個元素交換位置。     時間複雜度:平均時間複雜度為O(nlogn)
static void buildHeap(int [] array){
  //迴圈建堆  
        for(int i=0;i<array.length-1;i++){  
            //建堆  
            buildMinHeap(array,array.length-1-i);  
            //交換堆頂和最後一個元素  
            swap(array,0,array.length-1-i);  
            System.out.println(Arrays.toString(array));  
        }  
  }
    //對array陣列從0到lastIndex建大根堆
    static void buildMaxHeap(int[] array, int lastIndex){
         //從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(array[biggerIndex]<array[biggerIndex+1]){  
                        //biggerIndex總是記錄較大子節點的索引  
                        biggerIndex++;  
                    }  
                }  
                //如果k節點的值小於其較大的子節點的值  
                if(array[k]<array[biggerIndex]){  
                    //交換他們  
                    swap(array,k,biggerIndex);  
                    //將biggerIndex賦予k,開始while迴圈的下一次迴圈,重新保證k節點的值大於其左右子節點的值  
                    k=biggerIndex;  
                }else{  
                    break;  
                }  
            }
        }
    }
   
    //對array陣列從0到lastIndex建小根堆
    static void buildMinHeap(int[] array, int lastIndex){
         //從lastIndex處節點(最後一個節點)的父節點開始
        for(int i=(lastIndex-1)/2;i>=0;i--){
            //k儲存正在判斷的節點
            int k=i;
            //如果當前k節點的子節點存在  
            while(k*2+1<=lastIndex){
                //k節點的左子節點的索引
                int smallerIndex=2*k+1;
                //如果smallerIndex小於lastIndex,即smallerIndex+1代表的k節點的右子節點存在
                if(smallerIndex<lastIndex){  
                    //若果右子節點的值較小  
                    if(array[smallerIndex]>array[smallerIndex+1]){  
                        //smallerIndex總是記錄較小子節點的索引  
                     smallerIndex++;  
                    }  
                }  
                //如果k節點的值大於其較小的子節點的值  
                if(array[k]>array[smallerIndex]){  
                    //交換他們  
                    swap(array,k,smallerIndex);  
                    //將smallerIndex賦予k,開始while迴圈的下一次迴圈,重新保證k節點的值小於其左右子節點的值  
                    k=smallerIndex;  
                }else{  
                    break;  
                }  
            }
        }
    }
    //交換
    static void swap(int[] array, int i, int j) {  
        int temp=array[i];  
        array[i]=array[j];  
        array[j]=temp;  
    }

(6)氣泡排序(穩定排序)     基本思路:在要排序的一組數中,對當前還未排好序的範圍內的全部數,自上而下對相鄰的兩個數依次進行比較和調整,讓較大的數往下沉,較小的往上冒。即:每當兩相鄰的數比較後發現它們的排序與排序要求相反時,就將它們互換。     時間複雜度:平均時間複雜度為O(n^2)。
/*
  * 氣泡排序
  */
 static void bubSwapSort(int []array){
  int i,j,temp;
  Boolean flag=false;
        for (i = 0; i < array.length; i++) {
         flag=true;
            for(j=0;j<array.length-i-1;j++){
             if(array[j+1]<array[j])
             {
              temp=array[j+1];
              array[j+1]=array[j];
              array[j]=temp;
              flag=false;
             }
            }
            if(flag)
             break;
        }
 }


(7)快速排序(不穩定排序) 基本思路:選擇一個基準元素,通常選擇第一個元素或者最後一個元素,通過一趟掃描,將待排序列分成兩部分,一部分比基準元素小,一部分大於等於基準元素,此時基準元素在其排好序後的正確位置,然後再用同樣的方法遞迴地排序劃分的兩部分。     時間複雜度:平均時間複雜度為O(nlogn)
/*
  * 快速排序
  */
 static void quickSwapSort(int []array){
  if(array.length>0)
   quickSort(array,0,array.length-1);
 }
 static void quickSort(int []array,int start,int end){
  if(start<end){
   int mid=getMiddleIndex(array,start,end);
   quickSort(array,0,mid-1);
   quickSort(array,mid+1,end);
  }
 }
 static int getMiddleIndex(int []array,int start,int end){
  int temp=array[start];
  while(start<end){
   while(start<end&&array[end]>=temp)
    end--;
   array[start]=array[end];
   while(start<end&&array[start]<=temp)
    start++;
   array[end]=array[start];
  }
  array[start]=temp;
  return start;
 }

(8)歸併排序(穩定排序)     基本思路:將兩個(或兩個以上)有序表合併成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合併為整體有序序列。
平均時間複雜度為O(nlogn)
 /*
   * 歸併排序
   */
     static void mergeSort(int[] array, int left, int right) {
         if(left<right){
             int middle = (left+right)/2;
             //對左邊進行遞迴
             mergeSort(array, left, middle);
             //對右邊進行遞迴
             mergeSort(array, middle+1, right);
             //合併
             merge(array,left,middle,right);
         }
     }
     static void merge(int[] array, int left, int middle, int right) {
         int[] tempArray = new int[array.length];
         int middleRight = middle+1; //右邊的起始位置
         int temp = left;
         int third = left;
         while(left<=middle && middleRight<=right){
             //從兩個陣列中選取較小的數放入臨時陣列
             if(array[left]<=array[middleRight]){
                 tempArray[third++] = array[left++];
             }else{
                 tempArray[third++] = array[middleRight++];
             }
         }
         //將剩餘的部分放入臨時陣列
         while(left<=middle){
             tempArray[third++] = array[left++];
         }
         while(middleRight<=right){
             tempArray[third++] = array[middleRight++];
         }
         //將臨時陣列的排序結果複製到原陣列
         while(temp<=right){
          array[temp] = tempArray[temp++];
         }
     }

(9)基數排序(穩定排序)     基本思路:將所有待比較數值統一為同樣的數位長度,數位較短的數前面補零。從最低位開始,依次進行排序,從最低位一直排序到最高位,數列就變成一個有序序列。     時間複雜度:O(d(n+r)),d為位數,r為基數
/*
    * 基數排序
    */
     static void radixSort(int[] array) {
         //找到最大數,確定位數
         int max = 0;
         int times = 0;
         for (int i = 0; i < array.length; i++) {
             if(max<array[i]){
                 max = array[i];
             }
         }
         while(max>0){
             max = max/10;
             times++;
         }
         //建立數字列表
         List<ArrayList> list = new ArrayList<ArrayList>();
         for (int i = 0; i < 10; i++) {
             ArrayList<Integer> queue = new ArrayList<Integer>();
             list.add(queue);
         }
         int bit_num=0;
         int count = 0;
         for (int i = 0; i < times; i++) {
             for (int j = 0; j < array.length; j++) {
              bit_num = array[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i);
                 ArrayList<Integer> queue = list.get(bit_num);
                 queue.add(array[j]);
                 list.set(bit_num,queue);
             }
             //重新調整陣列
             count = 0;
             for (int j = 0; j < 10; j++) {
                 while(list.get(j).size()>0){
                     ArrayList<Integer> queue = list.get(j);
                     array[count++] = queue.get(0);
                     queue.remove(0);
                 }
             }
         }
     }

參考:

http://www.cnblogs.com/liuling/p/2013-7-24-01.html

http://www.cnblogs.com/Braveliu/archive/2013/01/15/2861201.html


相關推薦

基本排序演算法總結

排序分類: 1、插入排序:直接插入排序,二分法插入排序,希爾排序; 2、選擇排序:簡單選擇排序,堆排序; 3、交換排序:氣泡排序,快速排序; 4、歸併排序; 5、基數排序; (1)直接插入排序:(穩定排序)     基本思想:將每個待排序的記錄,按照其順序碼的大小插入到前

常用排序演算法總結

選擇排序、快速排序、希爾排序、堆排序不是穩定的排序演算法,氣泡排序、插入排序、歸併排序和基數排序是穩定的排序演算法。 冒泡法:  這是最原始,也是眾所周知的最慢的演算法了。他的名字的由來因為它的工作看來象是冒泡:  複雜度為O(n*n)。當資料為正序,將不會有交換。複雜度為

經典排序演算法詳解(氣泡排序,插入排序,選擇排序,快速排序,歸併排序,堆排序,計數排序,桶排序,基數排序

綜述 最近複習了各種排序演算法,記錄了一下學習總結和心得,希望對大家能有所幫助。本文介紹了氣泡排序、插入排序、選擇排序、快速排序、歸併排序、堆排序、計數排序、桶排序、基數排序9種經典的排序演算法。針對每種排序演算法分析了演算法的主要思路,每個演算法都附上了虛擬

經典排序演算法彙總

/*********************************************************** 總結各種排序演算法包括但不限於: 1. 插入排序類 1.1 直接插入排序 1.2 二分插入排序 1.3 希爾排序 2. 交換排序類 2.1 氣泡排序

7基本排序演算法--java實現

7種基本排序演算法有:直接插入排序、希爾排序;直接選擇排序、堆排序;氣泡排序、快速排序;歸併排序。實現如下:import java.util.Arrays; public class SortAlogrithm { public static void main(St

1T資料快速排序!十經典排序演算法總結

# 1 氣泡排序 每次迴圈都比較前後兩個元素的大小,如果前者大於後者,則將兩者進行交換。這樣做會將每次迴圈中最大的元素替換到末尾,逐漸形成有序集合。將每次迴圈中的最大元素逐漸由隊首**轉移**到隊尾的過程形似“冒泡”過程,故因此得名。 一個優化氣泡排序的方法就是如果在一次迴圈的過程中沒有發生交換,則可以立

基本排序演算法總結

準備函式 var arr = [] function swap(arr, a, b) { //交換函式 var temp = arr[a] arr[a] = arr[b] arr[b] = temp } function random_ar

排序演算法總結與Java實現

一、九種排序演算法總結 平均時間複雜度O(n^2): 氣泡排序、選擇排序、插入排序 平均時間複雜度O(nln):  快速排序、歸併排序、堆排序 時間複雜度介於O(nlgn)和O(n^2):希爾排序 時間複雜度O(n+k):計數排序 時間複雜度O(d(n+k)):基數排序

基本排序算法總結

子序列 system aop 大於等於 != pri i++ index 元素移動 以下均采用從小到大排序: 1.選擇排序算法 個人覺得選擇排序算法是容易理解的排序算法,即從n個元素中選擇最小的一個元素與第一個元素交換,再將除第一個元素之外的n-1個元素找到最小的一

基本排序演算法總結

# 插入排序 public static int[] insertSort2(int[] arr) { if (arr.length < 2 || arr == null) { return arr; } // 假設

初級排序演算法總結

@TOC 幾種初級排序演算法的總結 排序就是將一組物件按照某種邏輯順序重新排列的過程。 在本文中我們使用的操作: 遍歷陣列 比較兩個物件(本文中所有程式碼示例中的less方法) 交換兩個物件 (本文中所有程式碼示例中的

Java 八排序演算法總結

前言 一、簡介  二、演算法複雜度 三、常見演算法 (1)氣泡排序 (2)選擇排序 (3)插入排序 (4)歸併排序 (5)快速排序 (6)希爾排序 (7)基數排序 (8)堆排序 四、總結 五、Demo地址 六、參考文件

常用內部排序演算法總結

在公司實習了,由於公司的性質,以後的工作中用到演算法&資料結構的知識可能會很少,很想把以前學的資料結構&演算法的知識系統的回憶一下,但由於時間的原因,再加上我一直都很喜歡排序演算法的思想。近期主要就排序這個問題做一個系統的介紹:氣泡排序,簡單選擇排序,直接插

排序演算法總結(Java實現)

        排序演算法有很多,在特定情景中使用哪一種演算法很重要。本文對幾種常見排序演算法做了簡單的總結。 一、氣泡排序         氣泡排序(BubbleSort)是一種簡單的排序演算法。它重複地走訪要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交

機器學習的9個基礎概念和10基本算法總結

分割 比例 ssi 進一步 erro 所有 方程 相互 區間 https://blog.csdn.net/libaqiangdeliba/article/details/41901387 1.基礎概念:   (1) 10折交叉驗證:英文名是10-fold cross-v

Java 常用排序演算法總結

氣泡排序:  /*冒泡演算法*/ public class BubbleSort { public static void bubble_sort(int[] arr){ int temp; for(int i = 0; i < arr

11、【演算法排序演算法總結

常見排序演算法總結 一、氣泡排序 1、定義     氣泡排序是一種比較簡單的排序演算法,它會遍歷若干次要排序的數列,每次便利時,它都會從前往後依次的比較兩個相鄰的數的大小;如果前者比後者大,則交換它們的位置。     這樣一次遍歷之後,最大的元素就在數列的末尾了。採用相同的方法在

資料結構與演算法JavaScript描述讀書筆記(基本排序演算法

前提準備 //自動生成陣列的函式,n:整數個數,數字在l-r之間 function setData(n,l,r){ var dataStore = []; for(var i=0;i<n;i++){ dataStore[i] = Math.floor(

基本排序演算法-java實現

最近重新學習了排序演算法,之前每次看完當時理解了,但是過一段時間就又忘了,尤其是程式碼,如果放一段時間有很多base case不知道怎麼寫了,所以還是應該詳細的解讀一下再不斷了敲程式碼才能理解比較深刻。 1.氣泡排序(bubble sort) 氣泡排序是一種簡單的排序演算法。其基本思

常見排序演算法的比較和實現

首先排序演算法大的可以分為: 1、關鍵字比較 2、非關鍵字比較 關鍵字比較 關鍵字比較就是通過關鍵字之間的比較和移動,從而使整個序列有序, 而關鍵字比較的演算法,又可以像下面這樣劃分: 對於排序演算法之間的比較,無異於時間複雜度和空間複雜度。 從上表可以看出: 1、從平均時