日本好好热aⅴ|国产99视频精品免费观看|日本成人aV在线|久热香蕉国产在线

  • <cite id="ikgdy"><table id="ikgdy"></table></cite>
    1. 西西軟件園多重安全檢測下載網(wǎng)站、值得信賴的軟件下載站!
      軟件
      軟件
      文章
      搜索

      首頁編程開發(fā)VC|VC++ → C++經典排序算法全集

      C++經典排序算法全集

      相關軟件相關文章發(fā)表評論 來源:本站整理時間:2010/11/19 11:27:39字體大小:A-A+

      作者:佚名點擊:1318次評論:0次標簽: C 排序 算法 冒泡 交換

      • 類型:遠程監(jiān)控大。4.6M語言:中文 評分:5.7
      • 標簽:
      立即下載
      C++排序算法全集
      排序算法是一種基本并且常用的算法。由于實際工作中處理的數(shù)量巨大,所以排序算法對算法本身的速度要求很高。
      而一般我們所謂的算法的性能主要是指算法的復雜度,一般用O方法來表示。在后面我將給出詳細的說明。

      對于排序的算法我想先做一點簡單的介紹,也是給這篇文章理一個提綱。
      我將按照算法的復雜度,從簡單到難來分析算法。
      第一部分是簡單排序算法,后面你將看到他們的共同點是算法復雜度為O(N*N)(因為沒有使用word,所以無法打出上標和下標)。
      第二部分是高級排序算法,復雜度為O(Log2(N))。這里我們只介紹一種算法。另外還有幾種算法因為涉及樹與堆的概念,所以這里不于討論。
      第三部分類似動腦筋。這里的兩種算法并不是最好的(甚至有最慢的),但是算法本身比較奇特,值得參考(編程的角度)。同時也可以讓我們從另外的角度來認識這個問題。
      第四部分是我送給大家的一個餐后的甜點——一個基于模板的通用快速排序。由于是模板函數(shù)可以對任何數(shù)據(jù)類型排序(抱歉,里面使用了一些論壇專家的呢稱)。
       
      現(xiàn)在,讓我們開始吧:
       
      一、簡單排序算法
      由于程序比較簡單,所以沒有加什么注釋。所有的程序都給出了完整的運行代碼,并在我的VC環(huán)境下運行通過。因為沒有涉及MFC和WINDOWS的內容,所以在BORLAND C++的平臺上應該也不會有什么問題的。在代碼的后面給出了運行過程示意,希望對理解有幫助。

      1.冒泡法:
      這是最原始,也是眾所周知的最慢的算法了。他的名字的由來因為它的工作看來象是冒泡:
      #include <iostream.h>

      void BubbleSort(int* pData,int Count)
      {
      int iTemp;
      for(int i=1;i<Count;i++)
      {
       for(int j=Count-1;j>=i;j--)
       {
        if(pData[j]<pData[j-1])
        {
        iTemp = pData[j-1];
        pData[j-1] = pData[j];
        pData[j] = iTemp;
        }
       }
      }
      }

      void main()
      {
      int data[] = {10,9,8,7,6,5,4};
      BubbleSort(data,7);
      for (int i=0;i<7;i++)
       cout<<data<<" ";
      cout<<"\n";
      }

      倒序(最糟情況)
      第一輪:10,9,8,7->10,9,7,8->10,7,9,8->7,10,9,8(交換3次)
      第二輪:7,10,9,8->7,10,8,9->7,8,10,9(交換2次)
      第一輪:7,8,10,9->7,8,9,10(交換1次)
      循環(huán)次數(shù):6次
      交換次數(shù):6次

      其他:
      第一輪:8,10,7,9->8,10,7,9->8,7,10,9->7,8,10,9(交換2次)
      第二輪:7,8,10,9->7,8,10,9->7,8,10,9(交換0次)
      第一輪:7,8,10,9->7,8,9,10(交換1次)
      循環(huán)次數(shù):6次
      交換次數(shù):3次

      上面我們給出了程序段,現(xiàn)在我們分析它:這里,影響我們算法性能的主要部分是循環(huán)和交換,顯然,次數(shù)越多,性能就越差。從上面的程序我們可以看出循環(huán)的次數(shù)是固定的,為1+2+...+n-1。
      寫成公式就是1/2*(n-1)*n。
      現(xiàn)在注意,我們給出O方法的定義:

      若存在一常量K和起點n0,使當n>=n0時,有f(n)<=K*g(n),則f(n) = O(g(n))。(呵呵,不要說沒學好數(shù)學呀,對于編程數(shù)學是非常重要的。。。

      現(xiàn)在我們來看1/2*(n-1)*n,當K=1/2,n0=1,g(n)=n*n時,1/2*(n-1)*n<=1/2*n*n=K*g(n)。所以f(n) =O(g(n))=O(n*n)。所以我們程序循環(huán)的復雜度為O(n*n)。
      再看交換。從程序后面所跟的表可以看到,兩種情況的循環(huán)相同,交換不同。其實交換本身同數(shù)據(jù)源的有序程度有極大的關系,當數(shù)據(jù)處于倒序的情況時,交換次數(shù)同循環(huán)一樣(每次循環(huán)判斷都會交換),復雜度為O(n*n)。當數(shù)據(jù)為正序,將不會有交換。復雜度為O(0)。亂序時處于中間狀態(tài)。正是由于這樣的原因,我們通常都是通過循環(huán)次數(shù)來對比算法。


      2.交換法:
      交換法的程序最清晰簡單,每次用當前的元素一一的同其后的元素比較并交換。
      #include <iostream.h>
      void ExchangeSort(int* pData,int Count)
      {
      int iTemp;
      for(int i=0;i<Count-1;i++)
      {
       for(int j=i+1;j<Count;j++)
       {
        if(pData[j]<pData)
        {
        iTemp = pData;
        pData = pData[j];
        pData[j] = iTemp;
        }
       }
      }
      }

      void main()
      {
      int data[] = {10,9,8,7,6,5,4};
      ExchangeSort(data,7);
      for (int i=0;i<7;i++)
       cout<<data<<" ";
      cout<<"\n";
      }
      倒序(最糟情況)
      第一輪:10,9,8,7->9,10,8,7->8,10,9,7->7,10,9,8(交換3次)
      第二輪:7,10,9,8->7,9,10,8->7,8,10,9(交換2次)
      第一輪:7,8,10,9->7,8,9,10(交換1次)
      循環(huán)次數(shù):6次
      交換次數(shù):6次

      其他:
      第一輪:8,10,7,9->8,10,7,9->7,10,8,9->7,10,8,9(交換1次)
      第二輪:7,10,8,9->7,8,10,9->7,8,10,9(交換1次)
      第一輪:7,8,10,9->7,8,9,10(交換1次)
      循環(huán)次數(shù):6次
      交換次數(shù):3次

      從運行的表格來看,交換幾乎和冒泡一樣糟。事實確實如此。循環(huán)次數(shù)和冒泡一樣也是1/2*(n-1)*n,所以算法的復雜度仍然是O(n*n)。由于我們無法給出所有的情況,所以只能直接告訴大家他們在交換上面也是一樣的糟糕(在某些情況下稍好,在某些情況下稍差)。

      3.選擇法:
      現(xiàn)在我們終于可以看到一點希望:選擇法,這種方法提高了一點性能(某些情況下)
      這種方法類似我們人為的排序習慣:從數(shù)據(jù)中選擇最小的同第一個值交換,在從省下的部分中
      選擇最小的與第二個交換,這樣往復下去。
      #include <iostream.h>
      void SelectSort(int* pData,int Count)
      {
      int iTemp;
      int iPos;
      for(int i=0;i<Count-1;i++)
      {
       iTemp = pData;
       iPos = i;
       for(int j=i+1;j<Count;j++)
       {
        if(pData[j]<iTemp)
        {
        iTemp = pData[j];
        iPos = j;
        }
       }
       pData[iPos] = pData;
       pData = iTemp;
      }
      }

      void main()
      {
      int data[] = {10,9,8,7,6,5,4};
      SelectSort(data,7);
      for (int i=0;i<7;i++)
       cout<<data<<" ";
      cout<<"\n";
      }
      倒序(最糟情況)
      第一輪:10,9,8,7->(iTemp=9)10,9,8,7->(iTemp=8)10,9,8,7->(iTemp=7)7,9,8,10(交換1次)
      第二輪:7,9,8,10->7,9,8,10(iTemp=8)->(iTemp=8)7,8,9,10(交換1次)
      第一輪:7,8,9,10->(iTemp=9)7,8,9,10(交換0次)
      循環(huán)次數(shù):6次
      交換次數(shù):2次

      其他:
      第一輪:8,10,7,9->(iTemp=8)8,10,7,9->(iTemp=7)8,10,7,9->(iTemp=7)7,10,8,9(交換1次)
      第二輪:7,10,8,9->(iTemp=8)7,10,8,9->(iTemp=8)7,8,10,9(交換1次)
      第一輪:7,8,10,9->(iTemp=9)7,8,9,10(交換1次)
      循環(huán)次數(shù):6次
      交換次數(shù):3次
      遺憾的是算法需要的循環(huán)次數(shù)依然是1/2*(n-1)*n。所以算法復雜度為O(n*n)。
      我們來看他的交換。由于每次外層循環(huán)只產生一次交換(只有一個最小值)。所以f(n)<=n
      所以我們有f(n)=O(n)。所以,在數(shù)據(jù)較亂的時候,可以減少一定的交換次數(shù)。


      4.插入法:
      插入法較為復雜,它的基本工作原理是抽出牌,在前面的牌中尋找相應的位置插入,然后繼續(xù)下一張
      #include <iostream.h>
      void InsertSort(int* pData,int Count)
      {
      int iTemp;
      int iPos;
      for(int i=1;i<Count;i++)
      {
       iTemp = pData;
       iPos = i-1;
       while((iPos>=0) && (iTemp<pData[iPos]))
       {
        pData[iPos+1] = pData[iPos];
        iPos--;
       }
       pData[iPos+1] = iTemp;
      }
      }

      void main()
      {
      int data[] = {10,9,8,7,6,5,4};
      InsertSort(data,7);
      for (int i=0;i<7;i++)
       cout<<data<<" ";
      cout<<"\n";
      }

      倒序(最糟情況)
      第一輪:10,9,8,7->9,10,8,7(交換1次)(循環(huán)1次)
      第二輪:9,10,8,7->8,9,10,7(交換1次)(循環(huán)2次)
      第一輪:8,9,10,7->7,8,9,10(交換1次)(循環(huán)3次)
      循環(huán)次數(shù):6次
      交換次數(shù):3次

      其他:
      第一輪:8,10,7,9->8,10,7,9(交換0次)(循環(huán)1次)
      第二輪:8,10,7,9->7,8,10,9(交換1次)(循環(huán)2次)
      第一輪:7,8,10,9->7,8,9,10(交換1次)(循環(huán)1次)
      循環(huán)次數(shù):4次
      交換次數(shù):2次

      上面結尾的行為分析事實上造成了一種假象,讓我們認為這種算法是簡單算法中最好的,其實不是, 因為其循環(huán)次數(shù)雖然并不固定,我們仍可以使用O方法。從上面的結果可以看出,循環(huán)的次數(shù)f(n)<=1/2*n*(n-1)<=1/2*n*n。所以其復雜度仍為O(n*n)(這里說明一下,其實如果不是為了展示這些簡單排序的不同,交換次數(shù)仍然可以這樣推導)。現(xiàn)在看交換,從外觀上看,交換次數(shù)是O(n)(推導類似選擇法),但我們每次要進行與內層循環(huán)相同次數(shù)的‘=’操作。正常的一次交換我們需要三次‘=’而這里顯然多了一些,所以我們浪費了時間。

      最終,我個人認為,在簡單排序算法中,選擇法是最好的。


      二、高級排序算法:
      高級排序算法中我們將只介紹這一種,同時也是目前我所知道(我看過的資料中)的最快的。
      它的工作看起來仍然象一個二叉樹。首先我們選擇一個中間值middle程序中我們使用數(shù)組中間值,然后把比它小的放在左邊,大的放在右邊(具體的實現(xiàn)是從兩邊找,找到一對后交換)。然后對兩邊分別使用這個過程(最容易的方法——遞歸)。

      1.快速排序:
      #include <iostream.h>

      void run(int* pData,int left,int right)
      {
      int i,j;
      int middle,iTemp;
      i = left;
      j = right;
      middle = pData[(left+right)/2]; //求中間值
      do{
       while((pData<middle) && (i<right))//從左掃描大于中值的數(shù)
        i++;  
       while((pData[j]>middle) && (j>left))//從右掃描大于中值的數(shù)
        j--;
       if(i<=j)//找到了一對值
       {
        //交換
        iTemp = pData;
        pData = pData[j];
        pData[j] = iTemp;
        i++;
        j--;
       }
      }while(i<=j);//如果兩邊掃描的下標交錯,就停止(完成一次)

      //當左邊部分有值(left<j),遞歸左半邊
      if(left<j)
       run(pData,left,j);
      //當右邊部分有值(right>i),遞歸右半邊
      if(right>i)
       run(pData,i,right);
      }

      void QuickSort(int* pData,int Count)
      {
      run(pData,0,Count-1);
      }

      void main()
      {
      int data[] = {10,9,8,7,6,5,4};
      QuickSort(data,7);
      for (int i=0;i<7;i++)
       cout<<data<<" ";
      cout<<"\n";
      }

      這里我沒有給出行為的分析,因為這個很簡單,我們直接來分析算法:首先我們考慮最理想的情況
      1.數(shù)組的大小是2的冪,這樣分下去始終可以被2整除。假設為2的k次方,即k=log2(n)。
      2.每次我們選擇的值剛好是中間值,這樣,數(shù)組才可以被等分。
      第一層遞歸,循環(huán)n次,第二層循環(huán)2*(n/2)......
      所以共有n+2(n/2)+4(n/4)+...+n*(n/n) = n+n+n+...+n=k*n=log2(n)*n
      所以算法復雜度為O(log2(n)*n)
      其他的情況只會比這種情況差,最差的情況是每次選擇到的middle都是最小值或最大值,那么他將變成交換法(由于使用了遞歸,情況更糟)。但是你認為這種情況發(fā)生的幾率有多大??呵呵,你完全不必擔心這個問題。實踐證明,大多數(shù)的情況,快速排序總是最好的。
      如果你擔心這個問題,你可以使用堆排序,這是一種穩(wěn)定的O(log2(n)*n)算法,但是通常情況下速度要慢于快速排序(因為要重組堆)。

      三、其他排序
      1.雙向冒泡:
      通常的冒泡是單向的,而這里是雙向的,也就是說還要進行反向的工作。
      代碼看起來復雜,仔細理一下就明白了,是一個來回震蕩的方式。
      寫這段代碼的作者認為這樣可以在冒泡的基礎上減少一些交換(我不這么認為,也許我錯了)。
      反正我認為這是一段有趣的代碼,值得一看。
      #include <iostream.h>
      void Bubble2Sort(int* pData,int Count)
      {
      int iTemp;
      int left = 1;
      int right =Count -1;
      int t;
      do
      {
       //正向的部分
       for(int i=right;i>=left;i--)
       {
        if(pData<pData[i-1])
        {
        iTemp = pData;
        pData = pData[i-1];
        pData[i-1] = iTemp;
        t = i;
        }
       }
       left = t+1;

       //反向的部分
       for(i=left;i<right+1;i++)
       {
        if(pData<pData[i-1])
        {
        iTemp = pData;
        pData = pData[i-1];
        pData[i-1] = iTemp;
        t = i;
        }
       }
       right = t-1;
      }while(left<=right);
      }

      void main()
      {
      int data[] = {10,9,8,7,6,5,4};
      Bubble2Sort(data,7);
      for (int i=0;i<7;i++)
       cout<<data<<" ";
      cout<<"\n";
      }


      2.SHELL排序
      這個排序非常復雜,看了程序就知道了。
      首先需要一個遞減的步長,這里我們使用的是9、5、3、1(最后的步長必須是1)。
      工作原理是首先對相隔9-1個元素的所有內容排序,然后再使用同樣的方法對相隔5-1個元素的排序以次類推。
      #include <iostream.h>
      void ShellSort(int* pData,int Count)
      {
      int step[4];
      step[0] = 9;
      step[1] = 5;
      step[2] = 3;
      step[3] = 1;

      int iTemp;
      int k,s,w;
      for(int i=0;i<4;i++)
      {
       k = step;
       s = -k;
       for(int j=k;j<Count;j++)
       {
        iTemp = pData[j];
        w = j-k;//求上step個元素的下標
        if(s ==0)
        {
        s = -k;
        s++;
        pData[s] = iTemp;
        }
        while((iTemp<pData[w]) && (w>=0) && (w<=Count))
        {
        pData[w+k] = pData[w];
        w = w-k;
        }
        pData[w+k] = iTemp;
       }
      }
      }

      void main()
      {
      int data[] = {10,9,8,7,6,5,4,3,2,1,-10,-1};
      ShellSort(data,12);
      for (int i=0;i<12;i++)
       cout<<data<<" ";
      cout<<"\n";
      }
      呵呵,程序看起來有些頭疼。不過也不是很難,把s==0的塊去掉就輕松多了,這里是避免使用0步長造成程序異常而寫的代碼。這個代碼我認為很值得一看。 這個算法的得名是因為其發(fā)明者的名字D.L.SHELL。依照參考資料上的說法:“由于復雜的數(shù)學原因避免使用2的冪次步長,它能降低算法效率!绷硗馑惴ǖ膹碗s度為n的1.2次冪。同樣因為非常復雜并“超出本書討論范圍”的原因(我也不知道過程),我們只有結果了。


      四、基于模板的通用排序:
      這個程序我想就沒有分析的必要了,大家看一下就可以了。不明白可以在論壇上問。
      MyData.h文件
      ///////////////////////////////////////////////////////
      class CMyData
      {
      public:
      CMyData(int Index,char* strData);
      CMyData();
      virtual ~CMyData();

      int m_iIndex;
      int GetDataSize(){ return m_iDataSize; };
      const char* GetData(){ return m_strDatamember; };
      //這里重載了操作符:
      CMyData& operator =(CMyData &SrcData);
      bool operator <(CMyData& data );
      bool operator >(CMyData& data );

      private:
      char* m_strDatamember;
      int m_iDataSize;
      };
      ////////////////////////////////////////////////////////

      MyData.cpp文件
      ////////////////////////////////////////////////////////
      CMyData::CMyData():
      m_iIndex(0),
      m_iDataSize(0),
      m_strDatamember(NULL)
      {
      }

      CMyData::~CMyData()
      {
      if(m_strDatamember != NULL)
       delete[] m_strDatamember;
      m_strDatamember = NULL;
      }

      CMyData::CMyData(int Index,char* strData):
      m_iIndex(Index),
      m_iDataSize(0),
      m_strDatamember(NULL)
      {
      m_iDataSize = strlen(strData);
      m_strDatamember = new char[m_iDataSize+1];
      strcpy(m_strDatamember,strData);
      }

      CMyData& CMyData::operator =(CMyData &SrcData)
      {
      m_iIndex = SrcData.m_iIndex;
      m_iDataSize = SrcData.GetDataSize();
      m_strDatamember = new char[m_iDataSize+1];
      strcpy(m_strDatamember,SrcData.GetData());
      return *this;
      }

      bool CMyData::operator <(CMyData& data )
      {
      return m_iIndex<data.m_iIndex;
      }

      bool CMyData::operator >(CMyData& data )
      {
      return m_iIndex>data.m_iIndex;
      }
      ///////////////////////////////////////////////////////////

      //////////////////////////////////////////////////////////
      //主程序部分
      #include <iostream.h>
      #include "MyData.h"

      template <class T>
      void run(T* pData,int left,int right)
      {
      int i,j;
      T middle,iTemp;
      i = left;
      j = right;
      //下面的比較都調用我們重載的操作符函數(shù)
      middle = pData[(left+right)/2]; //求中間值
      do{
       while((pData<middle) && (i<right))//從左掃描大于中值的數(shù)
        i++;  
       while((pData[j]>middle) && (j>left))//從右掃描大于中值的數(shù)
        j--;
       if(i<=j)//找到了一對值
       {
        //交換
        iTemp = pData;
        pData = pData[j];
        pData[j] = iTemp;
        i++;
        j--;
       }
      }while(i<=j);//如果兩邊掃描的下標交錯,就停止(完成一次)

      //當左邊部分有值(left<j),遞歸左半邊
      if(left<j)
       run(pData,left,j);
      //當右邊部分有值(right>i),遞歸右半邊
      if(right>i)
       run(pData,i,right);
      }

      template <class T>
      void QuickSort(T* pData,int Count)
      {
      run(pData,0,Count-1);
      }

      void main()
      {
      CMyData data[] = {
       CMyData(8,"xulion"),
       CMyData(7,"sanzoo"),
       CMyData(6,"wangjun"),
       CMyData(5,"VCKBASE"),
       CMyData(4,"jacky2000"),
       CMyData(3,"cwally"),
       CMyData(2,"VCUSER"),
       CMyData(1,"isdong")
      };
      QuickSort(data,8);
      for (int i=0;i<8;i++)
       cout<<data.m_iIndex<<" "<<data.GetData()<<"\n";
      cout<<"\n";


      ////////////////////////////////////////////////////////
      經典C++雙向冒泡排序算法
      經典C++雙向冒泡排序算法
      hawkman2k 發(fā)表于 2003-12-09
      #include《iostream.h》
      #define max 20 //最多記錄個數(shù)
      typedef int elemtype;
      typedef elemtype recs[max];
      void bibubble(recs r,int n)
      {
      int flag=1; //繼續(xù)遍歷時flag置1,已排好序不需遍歷時為0
      int i=0, j;
      elemtype temp;
      while(flag==1)
      {
      flag=0;
      for(j=i+1;j《n-1;j++) //正向遍歷找最大值
      if(r[j]》r[j+1])
      {
      flag=1; //能交換時,說明未排好序,需繼續(xù)
      temp=r[j];
      r[j]=r[j+1];
      r[j+1]=temp;
      }
      for(j=n-i-1;j》=i+1;j--) //反向遍歷
      if(r[j]》r[j-1])
      {
      flag=1; //能交換時,說明未排好序,需繼續(xù)
      temp=r[j];
      r[j]=r[j-1];
      r[j-1]=temp;
      }
      i++;
      }
      }

      void main()
      {
      recs A={2,5,3,4,6,10,9,8,7,1};
      int n=10, i;
      cout《《"雙向冒泡排序"《《endl《《"排序前:";
      for(i=0;i《n;i++)
      cout《《A[i]《《"";
      cout《《endl;
      cout《《" 排序后: ";
      bibubble(A,n);
      for(i=0;i《n;i++)
      cout《《A[i]《《"";
      cout《《endl;
      }

        相關評論

        閱讀本文后您有什么感想? 已有人給出評價!

        • 8 喜歡喜歡
        • 3 頂
        • 1 難過難過
        • 5 囧
        • 3 圍觀圍觀
        • 2 無聊無聊

        熱門評論

        最新評論

        發(fā)表評論 查看所有評論(0)

        昵稱:
        表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
        字數(shù): 0/500 (您的評論需要經過審核才能顯示)