9種排序算法總結(jié)

各種排序算法復(fù)雜度比較

冒泡排序

兩兩比較,從底往上升。

  • 算法原理
    由最后一位開始,相鄰兩數(shù)兩兩比較,小的往上升,這樣一趟下來,最小的數(shù)就被排在了第一位,第二趟也是如此,如此類推,直到所有的數(shù)據(jù)排序完成

  • c++代碼實(shí)現(xiàn)

void bubble_sort(int arr[], int len)
{
      for (int i = 0; i < len - 1; i++)
      {
          for (int j = len - 1; j > i; j--)
          {
              if (arr[j] < arr[j - 1])
              {
                  int temp = arr[j];
                  arr[j] = arr[j - 1];
                  arr[j - 1] = temp;
              }
          }
      }
}

選擇排序

固定位置,找元素

  • 算法原理
    • 先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
    • 再從剩余未排序元素中繼續(xù)尋找最小(大)元素,然后放到已排序序列的末尾。
    • 以此類推,直到所有元素均排序完畢。
  • c++代碼實(shí)現(xiàn)
  void select_sort(int arr[], int len)
  {
      for (int i = 0; i < len; i++)
      {
          int index = i;
          for (int j = i + 1; j < len; j++)
          {
              if (arr[j] < arr[index])
                  index = j;
          }
          if (index != i)
          {
              int temp = arr[i];
              arr[i] = arr[index];
              arr[index] = temp; 
          }
      }
  }

插入排序

固定元素找位置

  • 算法原理
    將數(shù)據(jù)分為兩部分,有序部分與無序部分,一開始有序部分包含第1個(gè)元素,依次將無序的元素插入到有序部分,直到所有元素有序。插入排序又分為直接插入排序、二分插入排序、鏈表插入等,這里只討論直接插入排序。它是穩(wěn)定的排序算法,時(shí)間復(fù)雜度為O(n^2)
  • c++代碼實(shí)現(xiàn)
  void insert_sort(int arr[], int len)
  {
      for (int i = 1; i < len; i ++)
      {
          int j = i - 1;
          int k = arr[i];
          while (j > -1 && k < arr[j] )
          {
              arr[j + 1] = arr[j];
              j --;
          }
          arr[j + 1] = k;
      }
  }

快速排序

挖坑填數(shù)+分治法

  • 算法原理
    • 選擇一個(gè)基準(zhǔn)元素,第一個(gè)或最后一個(gè)
    • 通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨(dú)立的兩部分,其中一部分比基準(zhǔn)小,另外一部分比基準(zhǔn)大
    • 此時(shí)基準(zhǔn)已經(jīng)在其排好序后的位置
    • 然后再分別對(duì)這兩部分?jǐn)?shù)據(jù)用同樣的方法進(jìn)行排序,整個(gè)排序過程可以遞歸進(jìn)行,直到整個(gè)數(shù)據(jù)變成有序序列。
      總結(jié)
      1.i =L; j = R; 將基準(zhǔn)數(shù)挖出形成第一個(gè)坑a[i]。
      2.j--由后向前找比它小的數(shù),找到后挖出此數(shù)填前一個(gè)坑a[i]中。
      3.i++由前向后找比它大的數(shù),找到后也挖出此數(shù)填到前一個(gè)坑a[j]中。
      4.再重復(fù)執(zhí)行2,3二步,直到i==j,將基準(zhǔn)數(shù)填入a[i]中。
  • c++代碼實(shí)現(xiàn)
void quick_sort(int arr[], int left, int right)
{
    if (left < right)
    {
        int i = left, j = right, target = arr[left];
        while (i < j)
        {
            while (i < j && arr[j] > target)
                j--;
            if (i < j)
                arr[i++] = arr[j];

            while (i < j && arr[i] < target)
                i++;
            if (i < j)
                arr[j] = arr[i];
        }
        arr[i] = target;
        quick_sort(arr, left, i - 1);
        quick_sort(arr, i + 1, right);
    }
}

歸并排序

  • 算法原理
    假設(shè)序列共有n個(gè)元素:
    將序列每相鄰兩個(gè)數(shù)字進(jìn)行歸并操作(merge),形成floor(n/2)個(gè)序列,排序后每個(gè)序列包含兩個(gè)元素
    將上述序列再次歸并,形成floor(n/4)個(gè)序列,每個(gè)序列包含四個(gè)元素
    重復(fù)步驟2,直到所有元素排序完畢

  • c++代碼實(shí)現(xiàn)

  void merge(int arr[], int temp_arr[], int start_index, int mid_index, int end_index)
  {
      int first = start_index, second = mid_index + 1;
      int index = 0;
//比較二個(gè)數(shù)列的第一個(gè)數(shù),誰小就先取誰,取了后就在對(duì)應(yīng)數(shù)列中刪除這個(gè)數(shù),然后再進(jìn)行比較,直到有數(shù)列為空,
      while (first < mid_index + 1 && second < end_index + 1)
      {
          if (arr[first] > arr[second])
              temp_arr[index ++] = arr[second ++];
          else
              temp_arr[index ++] = arr[first ++];
      }
 //將另一個(gè)數(shù)列的數(shù)據(jù)依次取出即可
      while (first < mid_index + 1)
      {
          temp_arr[index ++] = arr[first ++];
      }
      while (second < end_index + 1)
          temp_arr[index ++] = arr[second ++];

      for (i = 0, j = start_index; j < end_index + 1; i ++, j ++)
          arr[j] = temp_arr[i];
  }

  void merge_sort(int arr[], int temp_arr[], int start_index, int end_index)
  {
      if (start_index < end_index)
      {
          int mid_index = (start_index + end_index) / 2;
          merge_sort(arr, temp_arr, start_index, mid_index);
          merge_sort(arr, temp_arr, mid_index + 1, end_index);
          merge(arr, temp_arr, start_index, mid_index, end_index);
      }
  }

堆排序

  • 算法原理(以最大堆為例)
    • 構(gòu)建大頂堆
      • 初始化堆
      • 從最后一個(gè)非葉節(jié)點(diǎn)開始調(diào)整
      • 每次調(diào)節(jié)都從父左右節(jié)點(diǎn)中選最大的同父節(jié)點(diǎn)交換
      • 交換之后可能導(dǎo)致被交換的孩子節(jié)點(diǎn)不滿足堆的性質(zhì),需要重新調(diào)整
    • 將堆頂元素通過最后一個(gè)元素 R[n] 交換
    • 由于交換后新堆頂可能違反堆的性質(zhì),因此需要重新調(diào)整為新堆,然后再次將 R[1]與無序區(qū)最后一個(gè)元素交換
  • 不斷重復(fù),直到有序區(qū)的個(gè)數(shù)為n-1
  • c++代碼實(shí)現(xiàn)
/**
 * 將數(shù)組arr構(gòu)建大根堆
 * @param arr 待調(diào)整的數(shù)組
 * @param i   待調(diào)整的數(shù)組元素的下標(biāo)
 * @param len 數(shù)組的長度
 */
void heap_adjust(int arr[], int i, int len)
{
    int child;
    int temp;

    for (; 2 * i + 1 < len; i = child)
    {
        child = 2 * i + 1;  // 子結(jié)點(diǎn)的位置 = 2 * 父結(jié)點(diǎn)的位置 + 1
        // 得到子結(jié)點(diǎn)中鍵值較大的結(jié)點(diǎn)
        if (child < len - 1 && arr[child + 1] > arr[child])
            child ++;
        // 如果較大的子結(jié)點(diǎn)大于父結(jié)點(diǎn)那么把較大的子結(jié)點(diǎn)往上移動(dòng),替換它的父結(jié)點(diǎn)
        if (arr[i] < arr[child])
        {
            temp = arr[i];
            arr[i] = arr[child];
            arr[child] = temp;
        }
        else
            break;
    }
}
/**
 * 堆排序算法
 */
void heap_sort(int arr[], int len)
{
    int i;
    // 調(diào)整序列的前半部分元素,調(diào)整完之后第一個(gè)元素是序列的最大的元素
    for (int i = len / 2 - 1; i >= 0; i--)
    {
        heap_adjust(arr, i, len);
    }

    for (i = len - 1; i > 0; i--)
    {
        // 將第1個(gè)元素與當(dāng)前最后一個(gè)元素交換,保證當(dāng)前的最后一個(gè)位置的元素都是現(xiàn)在的這個(gè)序列中最大的
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
        // 不斷縮小調(diào)整heap的范圍,每一次調(diào)整完畢保證第一個(gè)元素是當(dāng)前序列的最大值
        heap_adjust(arr, 0, i);
    }
}

希爾排序

分組插入排序,又稱縮小增量排序

  • 算法原理
    • 將整個(gè)待排元素分割成若干個(gè)序列(由相鄰某個(gè)增量的元素組成)
    • 將這些序列分別進(jìn)行直接插入排序
    • 縮減增量,再重復(fù)上述步驟
    • 待元素基本有序(增量足夠小時(shí))在對(duì)全體元素進(jìn)行一次直接插排
  • c++代碼實(shí)現(xiàn)
void shellsort3(int a[], int n)  
{  
    int i, j, gap;  
  
    for (gap = n / 2; gap > 0; gap /= 2)  
        for (i = gap; i < n; i++)  
            for (j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap)  
                Swap(a[j], a[j + gap]);  
}  

基數(shù)排序

  • 算法原理
    • 首先根據(jù)個(gè)位數(shù)的數(shù)值,在走訪數(shù)值時(shí)將它們分配至編號(hào)0到9的桶子中
    • 接下來將這些桶子中的數(shù)值重新串接起來,成為新的數(shù)列
    • 根據(jù)十位數(shù)數(shù)值來分配,重復(fù)上述步驟
    • 續(xù)進(jìn)行以上的動(dòng)作直至最高位數(shù)為止
  • c++代碼實(shí)現(xiàn)
//最大位數(shù)
int maxbit(int data[], int n)   
{  
    int d = 1; //保存最大的位數(shù)  
    int p = 10;  
    for(int i = 0; i < n; ++i)  
    {  
        while(data[i] >= p)  
        {  
![Uploading 273973-19cf4a1e58b6ebaf_927583.png . . .]
            p *= 10;  
            ++d;  
        }  
    }  
    return d;  
}  
//基數(shù)排序  
void radixsort(int data[], int n) 
{  
    int d = maxbit(data, n);  
    int tmp[n];  
    int count[10]; //計(jì)數(shù)器  
    int i, j, k;  
    int radix = 1;  
    for(i = 1; i <= d; i++) //進(jìn)行d次排序  
    {  
        for(j = 0; j < 10; j++)  
            count[j] = 0; //每次分配前清空計(jì)數(shù)器  
        for(j = 0; j < n; j++)  
        {  
            k = (data[j] / radix) % 10; //統(tǒng)計(jì)每個(gè)桶中的記錄數(shù)  
            count[k]++;  
        }  
        for(j = 1; j < 10; j++)  
            count[j] = count[j - 1] + count[j]; //將tmp中的位置依次分配給每個(gè)桶  
        for(j = n - 1; j >= 0; j--) //將所有桶中記錄依次收集到tmp中  
        {  
            k = (data[j] / radix) % 10;  
            tmp[count[k] - 1] = data[j];  
            count[k]--;  
        }  
        for(j = 0; j < n; j++) //將臨時(shí)數(shù)組的內(nèi)容復(fù)制到data中  
            data[j] = tmp[j];  
        radix = radix * 10;  
    }  
}  

計(jì)數(shù)排序

  • 算法原理
    • 遍歷一遍整個(gè)數(shù)組,找出數(shù)組中最大數(shù)和最小數(shù)之間的差距 range,然后開辟一個(gè)大小為range的數(shù)組count并全部初始化為0;
    • 再次遍歷整個(gè)數(shù)組,把每個(gè)元素的值映射到count的下標(biāo)index(val –> (val-min)),每映射到一個(gè)index,就把count[index]加一;
    • 根據(jù)統(tǒng)計(jì)結(jié)果count,把數(shù)寫會(huì)原數(shù)組,某個(gè)值index要寫count[index]遍到原數(shù)組,這樣,原數(shù)組就有序了
  • c++代碼實(shí)現(xiàn)
void CountSort(int *arr, int len)
{
    assert(arr);
    if(len <= 1)
        return ;

    int max = arr[0];
    int min = arr[0];
 //統(tǒng)計(jì)數(shù)組中的最大值和最小值
    for(int i = 0; i < len; ++i)   
    {
        if(arr[i] > max)
            max = arr[i];
        if(arr[i] < min)
            min = arr[i];
    }
    int range = max + 1 - min;  //得到最大最小值的差距
    int *count = new int[range];   //用于記錄數(shù)組中每個(gè)數(shù)字出現(xiàn)的次數(shù) 
    for(int i = 0; i < len; ++i)  // 初始化
        count[i] = 0;

    for(int i = 0; i < len; ++i)    
        count[ arr[i]-min ]++;  //arr[i] - min 映射到tmp中的一個(gè)下標(biāo),該下標(biāo)下的值是這個(gè)數(shù)出現(xiàn)的次數(shù)

    int index = 0;
    for(int i = 0; i < range; ++i)  //再把臨時(shí)數(shù)組記錄的數(shù)分別拷貝到原數(shù)組中
    {
        while(count[i]--)   //每個(gè)下標(biāo)下拷貝對(duì)應(yīng)的次數(shù)
            arr[index++] = i + min;
    }
} 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 概述排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部的...
    Luc_閱讀 2,299評(píng)論 0 35
  • 作者:大海里的太陽原文地址:http://www.cnblogs.com/wxisme/ 前言 查找和排序算法是算...
    IT程序獅閱讀 2,525評(píng)論 0 63
  • 1. 簡(jiǎn)介 本文借鑒了一位大神的文章,大神。單例的作用是在整個(gè)程序中,一個(gè)類只有一個(gè)實(shí)例,常見于播放器,管理類。優(yōu)...
    CJ_BLUE閱讀 1,220評(píng)論 0 1
  • 三個(gè)月前,給鳳凰科技投過簡(jiǎn)歷,那個(gè)時(shí)候鳳凰科技招聘兼職科技編譯的童鞋,雖然我有比較多的筆譯經(jīng)驗(yàn),但是很遺憾我不是專...
    Tomann16閱讀 290評(píng)論 0 3