程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 具體總結C++的排序算法

具體總結C++的排序算法

編輯:關於C++

具體總結C++的排序算法。本站提示廣大學習愛好者:(具體總結C++的排序算法)文章只能為提供參考,不一定能成為您想要的結果。以下是具體總結C++的排序算法正文


排序算法經由了很長時光的演化,發生了許多種分歧的辦法。關於初學者來講,對它們停止整頓便於懂得記憶顯得很主要。每種算法都有它特定的應用場所,很難通用。是以,我們很有需要對一切罕見的排序算法停止歸結。

我不愛好逝世記硬背,我更傾向於弄清前因後果,懂得性地記憶。好比上面這張時光龐雜度圖,我們將環繞這張圖來剖析。

下面的這張圖來自一個PPT。它歸納綜合了數據構造中的一切罕見的排序算法,給年夜家總結以下。

辨別穩固與不穩固:疾速、希爾、堆、選擇不穩固,其他排序算法均穩固。

均勻時光龐雜度:冒泡,選擇,拔出是O(n2),其他均是O(n*log2n)

最壞時光龐雜度:冒泡,選擇,拔出,快排是O(n2),其他是O(n*log2n)

均勻和最壞時光龐雜度:只要O(n2)和O(n*log2n)兩種,冒泡,選擇,拔出是O(n2),最壞情形下加一個快排,其他均是O(nlog2n)。

1、直接拔出排序(拔出排序)。

     1、算法的偽代碼(如許便於懂得):    

   INSERTION-SORT (A, n)       A[1 . . n] 
   for j ←2 to n 
     do key ← A[ j] 
     i ← j – 1 
     while i > 0 and A[i] > key 
        do A[i+1] ← A[i] 
          i ← i – 1 
     A[i+1] = key

     2、思惟:以下圖所示,每次選擇一個元素K拔出到之前已排好序的部門A[1…i]中,拔出進程中K順次由後向前與A[1…i]中的元素停止比擬。若發明發明A[x]>=K,則將K拔出到A[x]的前面,拔出前須要挪動元素。

     3、算法時光龐雜度。  

        最好的情形下:正序有序(從小到年夜),如許只須要比擬n次,不須要挪動。是以時光龐雜度為O(n)  

        最壞的情形下:逆序有序,如許每個元素就須要比擬n次,共有n個元素,是以現實龐雜度為O(n­2)  

       均勻情形下:O(n­2)

     4、穩固性。  

     懂得性記憶比逝世記硬背要好。是以,我們來剖析下。穩固性,就是有兩個雷同的元素,排序前後的絕對地位能否變更,重要用在排序時有多個排序規矩的情形下。在拔出排序中,K1是已排序部門中的元素,當K2和K1比擬時,直接插到K1的前面(沒有需要插到K1的後面,如許做還須要挪動!!),是以,拔出排序是穩固的。

2、希爾排序(拔出排序)

     1、思惟:希爾排序也是一種拔出排序辦法,現實上是一種分組拔出辦法。先取定一個小於n的整數d1作為第一個增量,把表的全體記載分紅d1個組,一切間隔為d1的倍數的記載放在統一個組中,在各組內停止直接拔出排序;然後,取第二個增量d2(<d1),反復上述的分組和排序,直至所取的增量dt=1

     例如:將 n 個記載分紅 d 個子序列: 

       { R[0],   R[d],     R[2d],…,     R[kd] } 
       { R[1],   R[1+d], R[1+2d],…,R[1+kd] }
         …
       { R[d-1],R[2d-1],R[3d-1],…,R[(k+1)d-1] }

    

     解釋:d=5 時,先從A[d]開端向前拔出,斷定A[d-d],然後A[d+1]與A[(d+1)-d]比擬,如斯類推,這一回合後將原序列分為d個組。<由後向前>

     2、時光龐雜度。  

     最好情形:因為希爾排序的利害和步長d的選擇有許多關系,是以,今朝還沒有得出最好的步長若何選擇(如今有些比擬好的選擇了,但不肯定能否是最好的)。所以,不曉得最好的情形下的算法時光龐雜度。  

     最壞情形下:O(N*logN),最壞的情形下戰爭均情形下差不多。  

     均勻情形下:O(N*logN)

     3、穩固性。  

     因為屢次拔出排序,我們曉得一次拔出排序是穩固的,不會轉變雷同元素的絕對次序,但在分歧的拔出排序進程中,雷同的元素能夠在各自的拔出排序中挪動,最初其穩固性就會被打亂,所以shell排序是不穩固的。(有個猜想,便利記憶:普通來講,若存在不相鄰元素間交流,則極可能是不穩固的排序。)

3、冒泡排序(交流排序)

       1、根本思惟:經由過程無序區中相鄰記載症結字間的比擬和地位的交流,使症結字最小的記載如氣泡普通逐步往上“漂浮”直至“水面”。

       

      2、時光龐雜度  

      最好情形下:正序有序,則只須要比擬n次。故,為O(n)  

      最壞情形下:  逆序有序,則須要比擬(n-1)+(n-2)+……+1,故,為O(N*N)

      3、穩固性  
      排序進程中只交流相鄰兩個元素的地位。是以,當兩個數相等時,是沒需要交流兩個數的地位的。所以,它們的絕對地位並沒有轉變,冒泡排序算法是穩固的!

4、疾速排序(交流排序)
     1、思惟:它是由冒泡排序改良而來的。在待排序的n個記載中任取一個記載(平日取第一個記載),把該記載放入恰當地位後,數據序列被此記載劃分紅兩部門。一切症結字比該記載症結字小的記載放置在前一部門,一切比它年夜的記載放置在後一部門,並把該記載排在這兩部門的中央(稱為該記載歸位),這個進程稱作一趟疾速排序。

     2、算法龐雜度  

      最好的情形下:由於每次都將序列分為兩個部門(普通二分都龐雜度都和logN相干),故為 O(N*logN)  

      最壞的情形下:根本有序時,退步為冒泡排序,簡直要比擬N*N次,故為O(N*N)

      3、穩固性  

      因為每次都須要和中軸元故舊換,是以本來的次序便可能被打亂。如序列為 5 3 3 4 3 8 9 10 11會將3的次序打亂。所以說,疾速排序是不穩固的!

5、直接選擇排序(選擇排序)

      1、思惟:起首在未排序序列中找到最小元素,寄存到排序序列的肇端地位,然後,再從殘剩未排序元素中持續尋覓最小元素,然後放到排序序列末尾。以此類推,直到一切元素均排序終了。詳細做法是:選擇最小的元素與未排序部門的首部交流,使得序列的後面為有序。  

      2、時光龐雜度。 

      最好情形下:交流0次,然則每次都要找到最小的元素,是以年夜約必需遍歷N*N次,是以為O(N*N)。削減了交流次數! 

      最壞情形下,均勻情形下:O(N*N)

      3、穩固性 

      因為每次都是拔取未排序序列A中的最小元素x與A中的第一個元故舊換,是以跨間隔了,極可能損壞了元素間的絕對地位,是以選擇排序是不穩固的!

6、堆排序

     1、思惟:應用完整二叉樹中雙親節點和孩子節點之間的內涵關系,在以後無序區當選擇症結字最年夜(或許最小)的記載。也就是說,以最小堆為例,根節點為最小元素,較年夜的節點傾向於散布在堆底鄰近。 

      2、算法龐雜度 

         最壞情形下,接近於最差情形下:O(N*logN),是以它是一種後果不錯的排序算法。

      3、穩固性 

         堆排序須要赓續地調劑堆,是以它是一種不穩固的排序!

7、合並排序

      1、思惟:屢次將兩個或兩個以上的有序表歸並成一個新的有序表。

       2、算法時光龐雜度 

          最好的情形下:一趟合並須要n次,總共須要logN次,是以為O(N*logN)  

         最壞的情形下,接近於均勻情形下,為O(N*logN) 

          解釋:對長度為n的文件,需停止logN 趟二路合並,每趟合並的時光為O(n),故當時間龐雜度不管是在最好情形下照樣在最壞情形下均是O(nlgn)。

      3、穩固性 
         合並排序最年夜的特點就是它是一種穩固的排序算法。合並進程中是不會轉變元素的絕對地位的。 
      4、缺陷是,它須要O(n)的額定空間。然則很合適於多鏈表排序。 
 

5、C++完成排序算法代碼總結以下:


#include<iostream>
#include<vector>
#include<limits>
using namespace std;
//拔出排序,相當於打牌,相當於把一個值拔出到曾經排序好的一個數組中,
//先把待排序的值放到一個暫時變量外面,讓排好序的數字從年夜到小去與這個值做比擬,若年夜於就把地位往後挪一個,
//騰出一個空地位出來,找到第一個小於他的地位就在該地位前面拔出此值,由於是原地排序,所以待排序的值也在數組中,
//默許數組中第一個值是曾經排好序的
void InsertSort(vector<int> &data)
{
    if(!data.empty())
        return;
    int size = data.size();
    for(int j = 1;j < size; ++j)//默許data[0]是排好序的
    {
        int temp = data[j];
        int index = j-1;
        while(index >= 0 && data[index] > temp)
        {
            data[index+1] = data[index];
            index--;
        }
        data[index+1] = temp;
    }
}
//合並排序,先分治,在合並
//假定sub1和sub2都是排好序的,result外面包括sub1和sub2中的一切元素
void Merge(vector<int> &result,vector<int> &sub1,vector<int> &sub2)
{
    sub1.push_back(INT_MAX);
    sub2.push_back(INT_MAX);
    int number1 = sub1.size();
    int number2 = sub2.size();
    int sub1_i = 0,sub2_i = 0;
    for(auto it = result.begin();it != result.end();++it)
    {
        if(sub1[sub1_i] <= sub2[sub2_i])
        {
            *it = sub1[sub1_i];
            ++sub1_i;
        }
        else
        {
            *it = sub2[sub2_i];
            ++sub2_i;
        }
    }
}
void MergeSort(vector<int>& coll)//歸並排序,先分治法,再歸並
{
    unsigned int number=coll.size();
    if(number<=1)
        return;
    unsigned int mid=number/2;
    vector<int> sub1;
    vector<int> sub2;
    for(unsigned int i=0;i<mid;++i)
    {
        sub1.push_back(coll[i]);
    }
    for(unsigned int j=0;j<number-mid;++j)
    {
        sub2.push_back(coll[mid+j]);
    }
    MergeSort(sub1);
    MergeSort(sub2);
    Merge(coll,sub1,sub2);
}
//冒泡排序法,每次老是拿以後輪回的值與還沒排好序的值停止比擬交流,把這一輪
//中最小的值放在以後輪回的下標數組中,每輪回一次,就排好一個較小的值,如許輪回n次,就排好序了
void BubleSort(vector<int> &data)
{
    int size = data.size();
    bool sort_flag = false;
    for(int i = 0;i < size;++i)
    {
        if(sort_flag == true) //冒泡改良版,當sort_flag = false;在某次輪回中沒有履行時,解釋剩下的元素都排好序了
            return;
        sort_flag = true;
        for(int j = i;j < size;++j)//經由一次輪回,將最小的值放在i處
        {
            if(data[i] > data[j])
            {
                swap(data[i],data[j]);
                sort_flag = false;
            }
        }
    }
}
//----------------------------------以下是不穩固排序算法-------------------------
//疾速排序
int Partition(int data[],int length,int start,int end)
{
    if(data == NULL || length <= 0 || start < 0 || end >= length)
        throw new exception(" Invalid Parameters");
    int index = rand()%(start-end+1)+start;
    swap(data[index],data[end]);
    int left = start-1;//小值放在右邊,年夜值放在左邊,輪回時,if前提不成立時解釋發明小值,不然一向值年夜值
    for(index = start;index < end;++index)
    {
        if(data[index] < data[end])
        {
            ++left;
            if(left != index)
            swap(data[left],data[index]);
        }
    }
    ++left;
    swap(data[left],data[end]);
    return left;
}
void QuickSort(int data[],int length,int start,int end)
{
    if(start == end)
        return;
    int index = Partition(data,length,start,end);
    if(index > start)
        QuickSort(data,length,start,index-1);
    if(index < end)
        QuickSort(data,length,index+1,end);
}
//堆排序 1.堆保護 2、建堆 3、堆排序
void MaxHeapIFY(vector<int> &data,int local,int length)//堆保護,local為要保護的元素的下標,length為數組的長度
{
    if(!data.empty())
        return;
    int left = local*2+1;//由於是從0開端計數,所以盤算公式有2i變成此公式
    int right = local*2;
    int largest = local;
    if(left < length && data[left] > data[local])
    {
        largest = left;
    }
    if(right < length && data[right] > data[local])
    {
        largest = right;
    }
    if(largest != local)
    {
        swap(data[largest],data[local]);
        MaxHeapIFY(data,largest,length);//largest為加入遞歸的前提,當他年夜於length時,即終止遞歸
    }
}
//建堆,是從第一個非葉子節點(length/2-1)停止堆保護
void BuileMaxHeap(vector<int> &data ,int length)
{
    int root = length/2-1;
    for(int i = root;i >= 0;--i)
    {
        MaxHeapIFY(data,i,length);
    }
}
//將第一個元素的值和最初一個元素互相交流,然後捨去最初一個元素,用剩下的n-1個元素停止堆保護,逐一遞加到最初一個元素
void HeapSort(vector<int> &data)
{
    if(!data.empty())
        return;
    BuileMaxHeap(data,data.size());
    int length = data.size();
    for(int i = length-1;i >= 0;--i)
    {
        swap(data[0],data[i]);
        --length;
        MaxHeapIFY(data,0,length);     
    }
}
//選擇排序,每次選擇一個本輪回中最小的值,與冒泡排序差不多,只不外少了交流的次數,是直接停止排序的
void SelectionSort(vector<int> &data)
{
    int size = data.size();
    --size;
    for(int i = 0;i < size-1;++i)
    {
        int min = i;
        for(int j = i+1;j < size;++j)
        {
            if(data[min] > data[j])
                min = j;
        }
        swap(data[min],data[i]);
    }
}
//希爾排序,思惟就是拔出排序,把待排序的數組分紅d組(下標每距離為d的停止元素為一組),然後每組停止拔出排序,
//接著遞加d的值,然後拔出排序,直到d=1最初的排序,如許比拔出排序來講,削減了排次序數,相當於跳著停止拔出排序,最初跳度為1
void ShellSort(vector<int> &data)
{
    int size = data.size();
    size;
    int separate = size / 2;
    while(separate > 0)
    {
        for(int i = separate;i < size;++i)
        {
            int temp = data[i];
            int j = i - separate;
            while(j >=0 && data[j] > temp)
            {
                data[j+separate] = data[j];
                j = j-separate;
            }
            data[j+separate] = temp;
        }
        separate /= 2;//遞加增量
    }
}

總結: 每種算法都要它實用的前提,本文也僅僅是回想了下基本。有須要的可以參考。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved