青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

陋居

淡薄名利,修身養性

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  31 Posts :: 1 Stories :: 4 Comments :: 0 Trackbacks

常用鏈接

留言簿

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

排序算法是一種基本并且常用的算法。由于實際工作中處理的數量巨大,所以排序算法對算法本身的速度要求很高。

  而一般我們所謂的算法的性能主要是指算法的復雜度,一般用O方法來表示。在后面我將給出詳細的說明。

  對于排序的算法我想先做一點簡單的介紹,也是給這篇文章理一個提綱。

  我將按照算法的復雜度,從簡單到難來分析算法。

  第一部分是簡單排序算法,后面你將看到他們的共同點是算法復雜度為O(N*N)(因為沒有使用word,所以無法打出上標和下標)。

  第二部分是高級排序算法,復雜度為O(Log2(N))。這里我們只介紹一種算法。另外還有幾種算法因為涉及樹與堆的概念,所以這里不于討論。

  第三部分類似動腦筋。這里的兩種算法并不是最好的(甚至有最慢的),但是算法本身比較奇特,值得參考(編程的角度)。同時也可以讓我們從另外的角度來認識這個問題。

  第四部分是我送給大家的一個餐后的甜點——一個基于模板的通用快速排序。由于是模板函數可以對任何數據類型排序(抱歉,里面使用了一些論壇專家的呢稱)。


  現在,讓我們開始吧:
  
一、簡單排序算法
由于程序比較簡單,所以沒有加什么注釋。所有的程序都給出了完整的運行代碼,并在我的VC環境下運行通過。因為沒有涉及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[i]<<" ";
  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次)
循環次數:6次
交換次數: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次)
循環次數:6次
交換次數:3次

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

  若存在一常量K和起點n0,使當n>=n0時,有f(n)<=K*g(n),則f(n) = O(g(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)。所以(n)=O(g(n))=O(n*n)。所以我們程序循環的復雜度為O(n*n)。
再看交換。從程序后面所跟的表可以看到,兩種情況的循環相同,交換不同。其實交換本身同數據源的有序程度有極大的關系,當數據處于倒序的情況時, 交換次數同循環一樣(每次循環判斷都會交換),復雜度為O(n*n)。當數據為正序,將不會有交換。復雜度為O(0)。亂序時處于中間狀態。正是由于這樣 的原因,我們通常都是通過循環次數來對比算法。


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[i])
      {
        iTemp = pData[i];
        pData[i] = 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[i]<<" ";
  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次)
循環次數:6次
交換次數: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次)
循環次數:6次
交換次數:3次

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

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

void main()
{
  int data[] = {10,9,8,7,6,5,4};
  SelectSort(data,7);
  for (int i=0;i<7;i++)
    cout<<data[i]<<" ";
  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次)
循環次數:6次
交換次數: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次)
循環次數:6次
交換次數:3次
遺憾的是算法需要的循環次數依然是1/2*(n-1)*n。所以算法復雜度為O(n*n)。
我們來看他的交換。由于每次外層循環只產生一次交換(只有一個最小值)。所以f(n)<=n
所以我們有f(n)=O(n)。
所以,在數據較亂的時候,可以減少一定的交換次數。


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

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

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

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

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


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

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[i]<middle) && (i<right))//從左掃描大于中值的數
      i++;     
    while((pData[j]>middle) && (j>left))//從右掃描大于中值的數
      j--;
    if(i<=j)//找到了一對值
    {
      //交換
      iTemp = pData[i];
      pData[i] = 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[i]<<" ";
  cout<<"\n";
}

這里我沒有給出行為的分析,因為這個很簡單,我們直接來分析算法:首先我們考慮最理想的情況
1.數組的大小是2的冪,這樣分下去始終可以被2整除。假設為2的k次方,即k=log2(n)。
2.每次我們選擇的值剛好是中間值,這樣,數組才可以被等分。
第一層遞歸,循環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都是最小值或最大值,那么他將變成交換法(由于使用了遞歸,情況更糟)。但是你認為這種情況發生的幾率有多大??呵呵,你完全不必擔心這個問題。實踐證明,大多數的情況,快速排序總是最好的。
如果你擔心這個問題,你可以使用堆排序,這是一種穩定的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[i]<pData[i-1])
      {
        iTemp = pData[i];
        pData[i] = pData[i-1];
        pData[i-1] = iTemp;
        t = i;
      }
    }
    left = t+1;

    //反向的部分
    for(i=left;i<right+1;i++)
    {
      if(pData[i]<pData[i-1])
      {
        iTemp = pData[i];
        pData[i] = 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[i]<<" ";
  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[i];
    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[i]<<" ";
  cout<<"\n";
}
呵呵,程序看起來有些頭疼。不過也不是很難,把s==0的塊去掉就輕松多了,這里是避免使用0步長造成程序異常而寫的代碼。這個代碼我認為很值得一看。
這個算法的得名是因為其發明者的名字D.L.SHELL。依照參考資料上的說法:“由于復雜的數學原因避免使用2的冪次步長,它能降低算法效率。”另外算法的復雜度為n的1.2次冪。同樣因為非常復雜并“超出本書討論范圍”的原因(我也不知道過程),我們只有結果了。

最后,希望大家愉快的編程。有什么意見,給我提吧!
posted on 2011-06-17 08:09 eircQ 閱讀(355) 評論(0)  編輯 收藏 引用 所屬分類: Arithmetic
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美日韩系列| 欧美激情精品久久久久久| 亚洲视频在线观看视频| 麻豆av福利av久久av| 国产综合色产在线精品| 久久资源在线| 欧美成人中文字幕在线| 亚洲激情在线视频| 99v久久综合狠狠综合久久| 欧美日韩国产成人在线免费| 亚洲免费成人av| 欧美日韩理论| 亚洲综合999| 久久国产精品一区二区三区| 亚洲三级影院| 午夜精品美女自拍福到在线| 国产综合网站| 99国产精品私拍| 激情成人亚洲| 亚洲婷婷综合色高清在线| 国内免费精品永久在线视频| 欧美国产日韩一区| 国产揄拍国内精品对白| 亚洲日本一区二区三区| 国产精品私房写真福利视频| 久久成人18免费网站| 久久综合给合久久狠狠色| 欧美日韩高清一区| 欧美激情亚洲视频| 在线观看不卡| 久久伊人精品天天| 久久精品二区三区| 国产精品一区在线观看你懂的| 亚洲成色777777女色窝| 国产一区视频在线观看免费| 99成人精品| 亚洲一区二区三区免费观看 | 欧美三级视频在线| 欧美韩日精品| 亚洲国产精品久久久久久女王| 日韩亚洲欧美成人| 亚洲精品影院| 国产精品久久久久9999高清| 欧美一区视频在线| 一区二区三区导航| 亚洲国产高清aⅴ视频| 久久久噜噜噜久久狠狠50岁| 亚洲小视频在线观看| 亚洲免费电影在线| 亚洲人成亚洲人成在线观看| 国内自拍一区| 欧美系列一区| 久久日韩粉嫩一区二区三区| 一本大道久久精品懂色aⅴ| 亚洲制服少妇| 99国产精品99久久久久久| 国产噜噜噜噜噜久久久久久久久| 噜噜噜噜噜久久久久久91 | 久久久午夜精品| 日韩亚洲欧美精品| 欧美 日韩 国产在线| 欧美成人dvd在线视频| 亚洲色无码播放| 亚洲精品在线视频观看| 亚洲第一在线| 久久久久久亚洲综合影院红桃| 99在线观看免费视频精品观看| 国产一级揄自揄精品视频| 国产酒店精品激情| 国内精品嫩模av私拍在线观看| 亚洲国产精品一区二区久| 欧美不卡一区| 国产精品草草| 国产日韩欧美在线视频观看| 国产精品综合久久久| 欧美性大战久久久久| 欧美日韩高清在线| 国产精品视频不卡| 国内成人精品一区| 亚洲国产精品久久91精品| 亚洲人成人一区二区三区| 99riav久久精品riav| 日韩亚洲欧美在线观看| 在线视频免费在线观看一区二区| 一区二区三区欧美| 篠田优中文在线播放第一区| 欧美一区影院| 欧美高清视频在线播放| 亚洲精品之草原avav久久| 亚洲在线中文字幕| 欧美肥婆在线| 国产日韩欧美另类| 亚洲国产小视频| 一区二区三区欧美日韩| 欧美一区二区日韩| 欧美激情第1页| 一区二区三区欧美视频| 欧美.www| 亚洲成色777777在线观看影院| 一本大道久久精品懂色aⅴ| 91久久国产综合久久蜜月精品 | 黑人巨大精品欧美黑白配亚洲| 国产精品久久婷婷六月丁香| 亚洲激情亚洲| 欧美插天视频在线播放| 久久国产手机看片| 亚洲高清在线观看| 午夜精品视频在线观看一区二区| 久久xxxx精品视频| 中国av一区| 国产精品无人区| 亚洲欧美日韩爽爽影院| 日韩亚洲欧美综合| 国产欧美日韩精品a在线观看| 亚洲影院在线| 亚洲综合欧美日韩| 国产欧美亚洲一区| 99国产精品久久久久久久久久 | 嫩草影视亚洲| 国产美女一区| 久久久国产一区二区三区| 午夜欧美不卡精品aaaaa| 国产酒店精品激情| 久久综合亚州| 欧美另类综合| 噜噜噜久久亚洲精品国产品小说| 欧美另类视频| 亚洲激情视频网站| 精品二区久久| 久久国产精品一区二区三区| 一区二区三区高清视频在线观看| 久久精品一区二区| 久久gogo国模啪啪人体图| 欧美吻胸吃奶大尺度电影| 亚洲韩国精品一区| 国产精品三区www17con| 玉米视频成人免费看| 韩国精品在线观看| 国产精品无码永久免费888| 一区二区三区国产在线观看| 夜夜嗨一区二区| 欧美 日韩 国产一区二区在线视频| 国产精品a久久久久久| 亚洲人午夜精品免费| 蜜臀av性久久久久蜜臀aⅴ四虎| 91久久在线播放| 欧美国产一区在线| 亚洲欧洲日本国产| 欧美激情视频在线免费观看 欧美视频免费一| 亚洲精品乱码久久久久久| 久久一二三区| 亚洲国产影院| 亚洲精品一区久久久久久| 欧美日韩精品一区二区三区| 91久久精品一区| 亚洲激情二区| 国产日韩欧美综合| 欧美高清视频在线| 国产精品电影观看| 亚洲大胆美女视频| 欧美日韩网站| 欧美1区2区| 欧美日韩国产一区二区三区| 亚洲欧洲视频| 亚洲欧美日韩高清| 亚洲精品乱码久久久久| 国产视频久久| 欧美日韩视频在线一区二区| 欧美一区二区视频观看视频| 欧美在线观看视频一区二区| 亚洲国产精品精华液2区45| 久久亚洲色图| 久久国产99| 欧美一级夜夜爽| 亚洲欧美区自拍先锋| 在线一区免费观看| 一二三区精品| 亚洲私拍自拍| 亚洲一区二区三区涩| 在线亚洲+欧美+日本专区| 日韩午夜在线视频| 亚洲欧洲综合| 日韩视频一区二区| 亚洲区在线播放| 亚洲精品国产欧美| 一二三区精品| 亚洲图片欧洲图片av| 亚洲一区美女视频在线观看免费| 在线一区二区日韩| 亚洲一区视频在线| 欧美影院久久久| 久久久久久精| 免费在线亚洲| 91久久在线| 亚洲一区二区三区在线| 性色av一区二区三区在线观看| 亚洲欧美日韩视频二区| 亚洲永久视频| 1000部国产精品成人观看| 在线观看日韩专区|