數據結構(十二)——排序算法

數據結構(十二)——排序算法

1、排序簡介

一、排序的通常定義

排序是計算機中常常進行的操做,目的在於將一組無序的數據元素調整爲有序的數據元素。
序列:1,20,45,5,2,12
排序後:1,2,5,12,20,45算法

二、排序的數學定義

數據結構(十二)——排序算法

三、排序的穩定性

若是序列中的兩個元素R[i]、R[j],關鍵字分別爲K[i]、K[j],而且在排序以前R[i]排在R[j]前面,若是排序操做後,元素R[i]仍然排在R[j]前面,則排序方法是穩定的;不然排序是不穩定的。數組

四、排序實現的關鍵

比較:任意兩個數據元素經過比較操做肯定前後次序。
交換:數據元素須要交換才能獲得預期的結果。數據結構

五、排序算法的性能評價

A、時間性能
主要性能差別體如今比較和交換的數量
B、輔助存儲空間
爲完成排序操做須要的額外的存儲空間
必要時能夠空間換時間
C、算法的實現複雜性
過於複雜的排序算法影響可讀性和可維護性ide

六、排序類

class Sort:public Object
  {
  private:
    Sort();
    Sort(const Sort& other);
    Sort& operator = (const Sort& other);
    template <typename T>
    static void Swap(T& a, T& b)
    {
      T temp;
      temp = a;
      a = b;
      b = temp;
    }
  }

2、選擇排序

一、選擇排序簡介

每次(第i次,i=1,2,3,...,n-2)從後面n-i個待排序的數據元素中選出關鍵字最小的元素,做爲有序序列的第i個元素。
第i次選擇排序示例:
數據結構(十二)——排序算法
選擇排序實例:
數據結構(十二)——排序算法
數據結構(十二)——排序算法函數

二、選擇排序的實現

選擇排序的實現:性能

/******************************************
     * 排序方式:選擇排序
     * array:序列
     * len:序列中元素個數
     * min2max:按從小到大進行排序
     * ***************************************/
    template <typename T>
    static void Select(T array[], int len, bool min2max = true)
    {
      for(int i = 0; i < len; i++)
      {
          int min = i;//從第i個元素開始
          //對待排序的元素進行比較
          for(int j = i + 1; j < len; j++)
          {
              //按排序的方式選擇比較方式
              if(min2max?(array[min] > array[j]):(array[min] < array[j]))
              {
                  min = j;
              }
          }
          if(min != i)
          {
             //元素交換
             Swap(array[i], array[min]);
          }
      }
    }

選擇排序的時間複雜度爲O(n^2)。
選擇排序是不穩定的排序方法。ui

3、插入排序

一、插入排序簡介

當插入第i(i>=1)個元素時,前i-1個元素已經排序好,用第i個元素的關鍵字與前i-1個元素的關鍵字分別進行比較,找到位置後將第i個元素插入,原來位置上的元素向後順移。
第i次插入排序示例:
數據結構(十二)——排序算法
插入排序實例:
數據結構(十二)——排序算法
數據結構(十二)——排序算法
數據結構(十二)——排序算法3d

二、插入排序的實現

/******************************************
 * 排序方式:插入排序
 * array:序列
 * len:序列中元素個數
 * min2max:按從小到大進行排序
 * ***************************************/
template <typename T>
static void Insert(T array[], int len, bool min2max = true)
{
    for(int i = 1; i < len; i++)
    {
            int k = i;
            T temp = array[i];
            for(int j = i -1; (j > 0) && (min2max?(array[j] > temp):(array[j] < temp)); j--)
            {
                    array[j + 1] = array[j];
                    k = j;
            }
            if(k != i)
            {
                    array[k] = temp;
            }
    }
}

插入排序的時間複雜度爲O(n^2)
插入排序是穩定的排序方法。代理

4、冒泡排序

一、冒泡排序簡介

每次從後向前進行(第i次),j=n-1,n-2,...,i,比較V[j-1]和V[j]的關鍵字,若是發生逆序,則交換V[j-1]和V[j]。
第i次冒泡排序示例:
數據結構(十二)——排序算法
冒泡排序實例:
數據結構(十二)——排序算法
數據結構(十二)——排序算法code

二、冒泡排序的實現

/**********************************************
 * 排序方式:冒泡排序
 * array:序列
 * len:序列中元素個數
 * min2max:按從小到大進行排序
 * *******************************************/
template <typename T>
static void Bubble(T array[], int len, bool min2max = true)
{
        bool exchange = true;
        //遍歷全部元素
        for(int i = 0; (i < len) && exchange; i++)
        {
                exchange = false;
                //將尾部元素與前面的每一個元素做比較交換
                for(int j = len - 1; j > i; j--)
                {
                        if(min2max?(array[j] < array[j-1]):(array[j] > array[j-1]))
                        {
                                //交換元素位置
                                Swap(array[j], array[j-1]);
                                exchange = true;
                        }
                }
        }
}

冒泡排序的時間複雜度爲O(n^2)
冒泡排序是穩定的排序方法。

5、希爾排序

一、希爾排序簡介

將待排序序列劃分爲若干組,在每一組內進行插入排序,以使整個序列基本有序,而後再對整個序列進行插入排序。
將n個數據元素分紅d個子序列,劃分方法以下:
數據結構(十二)——排序算法
d爲增量,d的值在排序過程當中由大到小逐漸縮小,直至最後一趟排序減爲1。
數據結構(十二)——排序算法
數據結構(十二)——排序算法
數據結構(十二)——排序算法

二、希爾排序的實現

/******************************************
 * 排序方式:希爾排序
 * array:序列
 * len:序列中元素個數
 * min2max:按從小到大進行排序
 * ***************************************/
template <typename T>
static void Shell(T array[], int len, bool min2max = true)
{
        int d = len;
        do
        {
             d = d/3 + 1;
             for(int i = d; i < len; i += d)
             {
                     int k = i;
                     T temp = array[i];
                     for(int j = i -d; (j >= 0) && (min2max?(array[j] > temp):(array[j] < temp)); j -= d)
                     {
                             array[j+d] = array[j];
                             k = j;
                     }
                     if(k != i)
                     {
                                array[k] = temp;
                     }
             }
        }while(d > 1);
}
};

希爾排序經過分組的方法進行屢次插入排序,是一種不穩定的排序方法,時間複雜度爲O(n^(3/2))。

6、歸併排序

一、歸併排序簡介

將兩個或兩個以上的有序序列合併成一個新的有序序列。
數據結構(十二)——排序算法
將2個有序序列歸併爲一個新的有序序列,稱爲2路歸併。
將N個有序序列歸併爲一個新的有序序列,稱爲N路歸併。
2路歸併實例:
數據結構(十二)——排序算法

二、歸併排序實現

template <typename T>
static void Merge(T src[], T helper[], int begin, int mid, int end, bool min2max=true)
{
        int i = begin;
        int j = mid + 1;
        int k = begin;
        while((i <= mid) && (j <= end))
        {
                if(min2max ? (src[i] < src[j]) : (src[i] > src[j]))
                {
                        helper[k++] = src[i++];
                }
                else
                {
                        helper[k++] = src[j++];
                }
        }
        while(i <= mid)
        {
                 helper[k++] = src[i++];
        }
        while(j <= end)
        {
                 helper[k++] = src[j++];
        }
        //拷貝輔助空間的結果到源序列空間
        for(i = begin; i <= end; i++)
        {
                src[i] = helper[i];
        }
}
template <typename T>
static void Merge(T src[], T helper[], int begin, int end, bool min2max=true)
{
        if(begin < end)
        {
                int mid = (begin + end) / 2;
                //左邊路進行歸併排序
                Merge(src, helper, begin, mid, min2max);
                //右邊路進行歸併排序
                Merge(src, helper, mid+1, end, min2max);
                //二路歸併排序
                Merge(src, helper, begin, mid, end, min2max);
        }
}
/******************************************
* 排序方式:歸併排序
* array: 序列
* len:序列中元素個數
* min2max:按從小到大進行排序
* ***************************************/
template <typename T>
static void Merge(T* array, int len, bool min2max=true)
{
    //輔助空間申請
    T* helper = new T[len];
    if(helper != NULL)
    {
        Merge(array, helper, 0, len-1, min2max);
    }
    delete [] helper;
}

歸併排序是一種穩定排序,須要額外的輔助空間完成,空間複雜度爲O(n),時間複雜度爲O(nlogn)。

7、快速排序

一、快速排序簡介

任取序列中的某個數據元素做爲基準將整個序列劃分爲左右兩個子序列。左側子序列中全部的數據元素都小於或等於基準元素,右側子序列中全部元素都大於基準元素,基準元素排在兩個子序列中間。
分別對兩個子序列進行從新劃分,直到全部的數據元素都排在相應位置上爲止。
快速排序示例:
數據結構(十二)——排序算法
快速排序實例:
數據結構(十二)——排序算法

二、快速排序實現

/******************************************
 * 快速排序的區域劃分函數
 * array:序列
 * begin:序列的起始位置
 * end:序列的結束位置
 * min2max:按從小到大進行排序
 * ***************************************/
template <typename T>
static int Partition(T array[], int begin, int end, bool min2max)
{
        T pv = array[begin];
        while(begin < end)
        {
                while((begin < end) && (min2max ? (array[end] > pv): (array[end] < pv)))
                {
                        end--;
                }
                Swap(array[begin], array[end]);
                while((begin < end) && (min2max ? (array[end] <= pv): (array[end] > pv)))
                {
                        begin++;
                }
                Swap(array[begin], array[end]);
        }
        array[begin] = pv;
        return begin;
}

/******************************************
 * 快速排序功能函數
 * array: 序列
 * begin:序列的起始位置
 * end: 序列的結束位置
 * min2max:按從小到大進行排序
 * ***************************************/
template <typename T>
static void Quick(T array[], int begin, int end, bool min2max)
{
        if(begin < end)
        {
            //對序列進行區域劃分
            int pivot = Partition(array, begin, end, min2max);
            //對基準左側的區域進行快排序
            Quick(array, begin, pivot, min2max);
            //對基準右側的區域進行塊排序
            Quick(array, pivot+1, end, min2max);
        }
}
/******************************************
* 排序方式:快速排序
* array: 序列
* len:序列中元素個數
* min2max:按從小到大進行排序
* ***************************************/
template <typename T>
static void Quick(T array[], int len, bool min2max=true)
{
    Quick(array, 0, len-1, min2max);
}

快速排序經過遞歸的方式對排序問題從新劃分,是一種不穩定的排序方法,時間複雜度爲O(nlogn)。

8、排序的工程應用

一、排序算法面向數組類的實現

template <typename T>
  static void Select(Array<T>& array, bool min2max=true)
  {
      Select(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Insert(Array<T>& array, bool min2max=true)
  {
      Insert(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Bubble(Array<T>& array, bool min2max=true)
  {
      Bubble(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Shell(Array<T>& array, bool min2max=true)
  {
      Shell(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Merge(Array<T>& array, bool min2max=true)
  {
      Merge(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Quick(Array<T>& array, bool min2max=true)
  {
      Quick(array.array(), array.length(), min2max);
  }

二、大規模序列的排序問題

排序過程當中不可避免的須要進行交換操做,交換操做的本質爲數據元素間的相互複製,若是序列的規模巨大時,交換操做將耗時巨大。經過使用代理模式,爲待排序元素設置代理對象,對代理對象組成的序列進行排序,須要訪問有序序列元素時,經過訪問待序列完成。經過使用空間換時間提升算法效率。

相關文章
相關標籤/搜索