當前位置:首頁 » 操作系統 » 演算法的代碼

演算法的代碼

發布時間: 2023-06-03 13:24:11

1. KMP演算法詳細代碼

private int KMP(String inText, String inMode)
{
if (inText.Length < inMode.Length)
{
return -1;
}

int[] arrNext = new int[inMode.Length + 1];
this.Next(inMode, arrNext);
int i, j; // i是主串游標 j是模式串游標
for (i = j = 0; i < inText.Length && j < inMode.Length; )
{
if (j == -1 || // 模式串游標已經回退到第一個位置
inText[i] == inMode[j]) // 當前字元匹配成功
{ // 滿足以上兩種情況時兩個游標都要向前進一步
++i;
++j;
}
else // 匹配不成功,模式串游標回退到當前字元的arrNext值
{
j = arrNext[j];
}
}
if (j >= inMode.Length)
{
return i - inMode.Length;
}
else
{
return -1;
}

}

private void Next(String inMode, int[] arrNext)
{
arrNext[0] = -1;
for (int i = 0, j = -1; i < inMode.Length; )
{ // i是主串游標 j是模式串的游標
if (j == -1 || // 如果模式串游標已經回退到第一個字元
inMode[i] == inMode[j]) // 如果匹配成功
{ // 兩個游標都向前走一步
++i;
++j;
arrNext[i] = j; // 存放當前的arrNext值為此時模式串的游標值
}
else // 匹配不成功j就回退到上一個arrNext值
{
j = arrNext[j];
}
}

}

2. 哈夫曼編碼的演算法代碼

//本程序根據26個英文字母出現的頻度,得到了它們的一種哈夫曼編碼方案 //by jirgal 2005.4.18 #include<iostream.h> #include<iomanip.h> #define NUM 26 //字母數 #define TNUM 51 // #define LTH 15 //編碼最大長度 class Node { public: char data; int weight; int parent; int lchild; int rchild; }; void main() { char ch[NUM]={'a','b','c','d','e','f','g','h','i','j','k','l', 'm','n','o','p','q','r','s','t','u','v','w','x','y','z'};//26個字母 int weit[NUM]={856,139,279,378,1304,289,199,528,627,13,42, 339,249,707,797,199,12,677,607,1045,249,92,149,17,199,8};//出現頻率 Node nodes[TNUM]; //用對象數組存儲哈夫曼樹 int i,j,one,two,a,b; int hc[NUM][LTH]; //用於存儲編碼 int m,n; //初始化數組 for(i=0;i<NUM;i++) { nodes[i].data=ch[i]; nodes[i].weight=weit[i]; nodes[i].parent=-1; nodes[i].lchild=-1; nodes[i].rchild=-1; } for(i=NUM;i<TNUM;i++) { nodes[i].data='@'; nodes[i].weight=-1; nodes[i].parent=-1; nodes[i].lchild=-1; nodes[i].rchild=-1; } //建立哈夫曼樹 for(i=NUM;i<TNUM;i++) { a=b=-1; one=two=10000; //最大權數 for(j=0;j<i;j++) { if(nodes[j].parent==-1) if(nodes[j].weight<=two) one=two; two=nodes[j].weight; a=b; b=j; } else if(nodes[j].weight>two&&nodes[j].weight<=one) { one=nodes[j].weight; a=j; } } }//for語句得到 parent=-1(即尚沒有父結點)且weight最小的兩個結點 nodes[a].parent=i; nodes[b].parent=i; nodes[i].lchild=a; nodes[i].rchild=b; nodes[i].weight=nodes[a].weight+nodes[b].weight; } //初始化hc for(i=0;i<LTH;i++) { for(j=0;j<NUM;j++) { hc[j][i]=7; } } //編碼 for(i=0;i<NUM;i++) { j=LTH-1; for(m=i,n=nodes[i].parent;m!=-1;m=n,n=nodes[n].parent) { if(nodes[n].lchild==m) { hc[i][j]=0; } else { hc[i][j]=1; } j--; } } //輸出 nodes cout<<"HuffmanTree:"<<endl; cout<<setw(4)<<"NO."<<setw(6)<<"data"<<setw(8)<<"weight"<<setw(6) <<"parnt"<<setw(6)<<"lchd"<<setw(6)<<"rchd"<<endl; for(i=0;i<TNUM;i++) { cout<<setw(4)<<i<<setw(6)<<nodes[i].data<<setw(8)<<nodes[i].weight<<setw(6) <<nodes[i].parent<<setw(6)<<nodes[i].lchild<<setw(6)<<nodes[i].rchild<<endl; } //輸出編碼 cout<<endl<<"Result:"<<endl; cout<<setw(6)<<"char"<<setw(10)<<"frequency"<<setw(16)<<"huffmancode\n"; for(i=0;i<NUM;i++) { cout<<setw(6)<<ch[i]<<setw(8)<<weit[i]; cout<<" "; for(j=0;j<LTH;j++) { if(hc[i][j]!=7) { cout<<hc[i][j]; } } cout<<endl; } cout<<"\nDone.\n"<<endl; }

3. C語言實現七種排序演算法的演示代碼是什麼

(1)「冒泡法」
冒泡法大家都較熟悉。其原理為從a[0]開始,依次將其和後面的元素比較,若a[0]>a[i],則交換它們,一直比較到a[n]。同理對a[1],a[2],...a[n-1]處理,即完成排序。下面列出其代碼:
void
bubble(int
*a,int
n)
/*定義兩個參數:數組首地址與數組大小*/
{
int
i,j,temp;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
/*注意循環的上下限*/
if(a[i]>a[j])
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
冒泡法原理簡單,但其缺點是交換次數多,效率低。
下面介紹一種源自冒泡法但更有效率的方法「選擇法」。
(2)「選擇法」
選擇法循環過程與冒泡法一致,它還定義了記號k=i,然後依次把a[k]同後面元素比較,若a[k]>a[j],則使k=j.最後看看k=i是否還成立,不成立則交換a[k],a[i],這樣就比冒泡法省下許多無用的交換,提高了效率。
void
choise(int
*a,int
n)
{
int
i,j,k,temp;
for(i=0;i<n-1;i++)
{
k=i;
/*給記號賦值*/
for(j=i+1;j<n;j++)
if(a[k]>a[j])
k=j;
/*是k總是指向最小元素*/
if(i!=k)
{
/*當k!=i是才交換,否則a[i]即為最小*/
temp=a[i];
a[i]=a[k];
a[k]=temp;
}
}
}
選擇法比冒泡法效率更高,但說到高效率,非「快速法」莫屬,現在就讓我們來了解它。
(3)「快速法」
快速法定義了三個參數,(數組首地址*a,要排序數組起始元素下標i,要排序數組結束元素下標j).
它首先選一個數組元素(一般為a[(i+j)/2],即中間元素)作為參照,把比它小的元素放到它的左邊,比它大的放在右邊。然後運用遞歸,在將它左,右兩個子數組排序,最後完成整個數組的排序。下面分析其代碼:
void
quick(int
*a,int
i,int
j)
{
int
m,n,temp;
int
k;
m=i;
n=j;
k=a[(i+j)/2];
/*選取的參照*/
do
{
while(a[m]<k&&m<j)
m++;
/*
從左到右找比k大的元素*/
while(a[n]>k&&n>i)
n--;
/*
從右到左找比k小的元素*/
if(m<=n)
{
/*若找到且滿足條件,則交換*/
temp=a[m];
a[m]=a[n];
a[n]=temp;
m++;
n--;
}
}while(m<=n);
if(m<j)
quick(a,m,j);
/*運用遞歸*/
if(n>i)
quick(a,i,n);
}
(4)「插入法」
插入法是一種比較直觀的排序方法。它首先把數組頭兩個元素排好序,再依次把後面的元素插入適當的位置。把數組元素插完也就完成了排序。
void
insert(int
*a,int
n)
{
int
i,j,temp;
for(i=1;i<n;i++)
{
temp=a[i];
/*temp為要插入的元素*/
j=i-1;
while(j>=0&&temp<a[j])
{
/*從a[i-1]開始找比a[i]小的數,同時把數組元素向後移*/
a[j+1]=a[j];
j--;
}
a[j+1]=temp;
/*插入*/
}
}
(5)「shell法」
shell法是一個叫
shell
的美國人與1969年發明的。它首先把相距k(k>=1)的那幾個元素排好序,再縮小k值(一般取其一半),再排序,直到k=1時完成排序。下面讓我們來分析其代碼:
void
shell(int
*a,int
n)
{
int
i,j,k,x;
k=n/2;
/*間距值*/
while(k>=1)
{
for(i=k;i<n;i++)
{
x=a[i];
j=i-k;
while(j>=0&&x<a[j])
{
a[j+k]=a[j];
j-=k;
}
a[j+k]=x;
}
k/=2;
/*縮小間距值*/
}
}
上面我們已經對幾種排序法作了介紹,現在讓我們寫個主函數檢驗一下。
#include<stdio.h>
/*別偷懶,下面的"..."代表函數體,自己加上去哦!*/
void
bubble(int
*a,int
n)
{
...
}
void
choise(int
*a,int
n)
{
...
}
void
quick(int
*a,int
i,int
j)
{
...
}
void
insert(int
*a,int
n)
{
...
}
void
shell(int
*a,int
n)
{
...
}
/*為了列印方便,我們寫一個print吧。*/[code]
void
print(int
*a,int
n)
{
int
i;
for(i=0;i<n;i++)
printf("%5d",a[i]);
printf("\n");
}
main()
{
/*為了公平,我們給每個函數定義一個相同數組*/
int
a1[]={13,0,5,8,1,7,21,50,9,2};
int
a2[]={13,0,5,8,1,7,21,50,9,2};
int
a3[]={13,0,5,8,1,7,21,50,9,2};
int
a4[]={13,0,5,8,1,7,21,50,9,2};
int
a5[]={13,0,5,8,1,7,21,50,9,2};
printf("the
original
list:");
print(a1,10);
printf("according
to
bubble:");
bubble(a1,10);
print(a1,10);
printf("according
to
choise:");
choise(a2,10);
print(a2,10);
printf("according
to
quick:");
quick(a3,0,9);
print(a3,10);
printf("according
to
insert:");
insert(a4,10);
print(a4,10);
printf("according
to
shell:");
shell(a5,10);
print(a5,10);
}

4. 加密演算法實現代碼

這個是界面效果,我不是用C++寫的,是用C#寫的可以參考下:

實現的代碼如下:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.ComponentModel;

usingSystem.Data;

usingSystem.Drawing;

usingSystem.Text;

usingSystem.Windows.Forms;

usingSystem.Collections;

usingSystem.IO;

usingSystem.Security.Cryptography;

usingSystem.Security;

namespaceKey

{

publicpartialclassfrmKey:Form

{

privatestringkey;//默認密鑰"yupengcheng"

privatebyte[]sKey;

privatebyte[]sIV;

publicfrmKey()

{

InitializeComponent();

}

privatevoidForm1_Load(objectsender,EventArgse)

{

button4.Enabled=false;

}

///<summary>

///選擇輸入路徑

///</summary>

privatevoidbutton1_Click(objectsender,EventArgse)

{

//openFileDialog1.Filter="所有文件(*.*)|*.*";

openFileDialog1.ShowDialog();

stringfilename=openFileDialog1.FileName;

inti=filename.LastIndexOf(".");

if(i!=-1)

{

stringfiletype=filename.Substring(filename.LastIndexOf("."));

if(this.radioButton1.Checked)

{

filename=filename.Replace("(解密文件)","");

textBox2.Text=filename.Substring(0,filename.LastIndexOf("."))+"(加密文件)"+filetype;

}

else

{

filename=filename.Replace("(加密文件)","");

textBox2.Text=filename.Substring(0,filename.LastIndexOf("."))+"(解密文件)"+filetype;

}

}

if(filename!="")

{

textBox1.Text=openFileDialog1.FileName;

}

}

///<summary>

///選擇輸出路徑

///</summary>

privatevoidbutton4_Click(objectsender,EventArgse)

{

this.saveFileDialog1.ShowDialog();

if(saveFileDialog1.FileName!="")

{

this.textBox2.Text=saveFileDialog1.FileName;

}

}

///<summary>

///加密radioButton

///</summary>

privatevoidradioButton1_CheckedChanged(objectsender,EventArgse)

{

button3.Text="開始加密";

}

///<summary>

///解密radioButton

///</summary>

privatevoidradioButton2_CheckedChanged(objectsender,EventArgse)

{

button3.Text="開始解密";

}

///<summary>

///明密/暗密

///</summary>

privatevoidbutton2_Click(objectsender,EventArgse)

{

if(button2.Text=="明密")

{

textBox3.PasswordChar=Convert.ToChar(0);

button2.Text="暗密";

}

else

{

textBox3.PasswordChar=char.Parse("*");

button2.Text="明密";

}

}

///<summary>

///開始加密/開始解密

///</summary>

privatevoidbutton3_Click(objectsender,EventArgse)

{

if(this.textBox1.Text==""||this.textBox2.Text=="")

{

MessageBox.Show("文件路徑不能為空!","警告提示",MessageBoxButtons.OK,MessageBoxIcon.Warning);

return;

}

if(textBox3.Text!="yupengcheng")

{

MessageBox.Show("輸入的密碼不正確,請重新輸入!","錯誤提示",MessageBoxButtons.OK,MessageBoxIcon.Error);

textBox3.Text="";

return;

}

else

{

key="yupengcheng";

if(button3.Text=="開始加密")

{

statusBar1.Visible=true;

statusBar1.Text="正在加密文件,請等待.....";

if(EncryptFile(this.textBox1.Text,this.textBox2.Text,textBox3.Text))

{

statusBar1.Text="加密完成。";

MessageBox.Show("文件加密成功!","成功提示",MessageBoxButtons.OK,MessageBoxIcon.Information);

}

statusBar1.Visible=false;

}

else

{

statusBar1.Visible=true;

statusBar1.Text="正在解密文件,請等待.....";

if(DecryptFile(this.textBox1.Text,this.textBox2.Text,textBox3.Text))

{

statusBar1.Text="解密完成。";

MessageBox.Show("文件解密成功!","成功提示",MessageBoxButtons.OK,MessageBoxIcon.Information);

}

statusBar1.Visible=false;

}

}

}

///<summary>

///取消

///</summary>

privatevoidbutton5_Click(objectsender,EventArgse)

{

Application.Exit();

}

///<summary>

///加密方法

///</summary>

///<paramname="filePath">加密輸入路徑</param>

///<paramname="savePath">加密輸出路徑</param>

///<paramname="keyStr">密匙</param>

///<returns></returns>

publicboolEncryptFile(stringfilePath,stringsavePath,stringkeyStr)

{

DESCryptoServiceProviderdes=newDESCryptoServiceProvider();

if(keyStr=="")

keyStr=key;

try

{

FileStreamfs=File.OpenRead(filePath);

byte[]inputByteArray=newbyte[fs.Length];

fs.Read(inputByteArray,0,(int)fs.Length);

fs.Close();

byte[]keyByteArray=Encoding.Default.GetBytes(keyStr);

SHA1ha=newSHA1Managed();

byte[]hb=ha.ComputeHash(keyByteArray);

sKey=newbyte[8];

sIV=newbyte[8];

for(inti=0;i<8;i++)

sKey[i]=hb[i];

for(inti=8;i<16;i++)

sIV[i-8]=hb[i];

des.Key=sKey;

des.IV=sIV;

MemoryStreamms=newMemoryStream();

CryptoStreamcs=newCryptoStream(ms,des.CreateEncryptor(),CryptoStreamMode.Write);

cs.Write(inputByteArray,0,inputByteArray.Length);

cs.FlushFinalBlock();

fs=File.OpenWrite(savePath);

foreach(bytebinms.ToArray())

{

fs.WriteByte(b);

}

fs.Close();

cs.Close();

ms.Close();

returntrue;

}

catch

{

MessageBox.Show("找不到指定的文件,請重新輸入!","警告提示",MessageBoxButtons.OK,MessageBoxIcon.Warning);

returnfalse;

}

}

///<summary>

///解密方法

///</summary>

///<paramname="filePath">解密輸入路徑</param>

///<paramname="savePath">解密輸出路徑</param>

///<paramname="keyStr">密匙</param>

///<returns></returns>

publicboolDecryptFile(stringfilePath,stringsavePath,stringkeyStr)

{

DESCryptoServiceProviderdes=newDESCryptoServiceProvider();

if(keyStr=="")

keyStr=key;

try

{

FileStreamfs=File.OpenRead(filePath);

byte[]inputByteArray=newbyte[fs.Length];

fs.Read(inputByteArray,0,(int)fs.Length);

fs.Close();

byte[]keyByteArray=Encoding.Default.GetBytes(keyStr);

SHA1ha=newSHA1Managed();

byte[]hb=ha.ComputeHash(keyByteArray);

sKey=newbyte[8];

sIV=newbyte[8];

for(inti=0;i<8;i++)

sKey[i]=hb[i];

for(inti=8;i<16;i++)

sIV[i-8]=hb[i];

des.Key=sKey;

des.IV=sIV;

MemoryStreamms=newMemoryStream();

CryptoStreamcs=newCryptoStream(ms,des.CreateDecryptor(),CryptoStreamMode.Write);

cs.Write(inputByteArray,0,inputByteArray.Length);

cs.FlushFinalBlock();

fs=File.OpenWrite(savePath);

foreach(bytebinms.ToArray())

{

fs.WriteByte(b);

}

fs.Close();

cs.Close();

ms.Close();

returntrue;

}

catch

{

MessageBox.Show("找不到指定的文件,請重新輸入!","警告提示",MessageBoxButtons.OK,MessageBoxIcon.Warning);

returnfalse;

}

}

privatevoidtextBox1_TextChanged(objectsender,EventArgse)

{

if(textBox1.Text==""||textBox1.Text==null)

{

button4.Enabled=false;

}

else

{

button4.Enabled=true;

}

}

}

}

5. 求一個A*演算法的C語言或C++代碼,小弟不勝感激,謝謝

1#include <iostream>
2#include <queue>
3usingnamespace std;
4
5struct knight{
6int x,y,step;
7int g,h,f;
8booloperator< (const knight & k) const{ //重載比較運算符
9return f > k.f;
10 }
11}k;
12bool visited[8][8]; //已訪問標記(關閉列表)
13int x1,y1,x2,y2,ans; //起點(x1,y1),終點(x2,y2),最少移動次數ans
14int dirs[8][2]={{-2,-1},{-2,1},{2,-1},{2,1},{-1,-2},{-1,2},{1,-2},{1,2}};//8個移動方向
15priority_queue<knight> que; //最小優先順序隊列(開啟列表)
16
17boolin(const knight & a){ //判斷knight是否在棋盤內
18if(a.x<0|| a.y<0|| a.x>=8|| a.y>=8)
19returnfalse;
20returntrue;
21}
22int Heuristic(const knight &a){ //manhattan估價函數
23return (abs(a.x-x2)+abs(a.y-y2))*10;
24}
25void Astar(){ //A*演算法
26 knight t,s;
27while(!que.empty()){
28 t=que.top(),que.pop(),visited[t.x][t.y]=true;
29if(t.x==x2 && t.y==y2){
30 ans=t.step;
31break;
32 }
33for(int i=0;i<8;i++){
34 s.x=t.x+dirs[i][0],s.y=t.y+dirs[i][1];
35if(in(s) &&!visited[s.x][s.y]){
36 s.g = t.g +23; //23表示根號5乘以10再取其ceil
37 s.h = Heuristic(s);
38 s.f = s.g + s.h;
39 s.step = t.step +1;
40 que.push(s);
41 }
42 }
43 }
44}
45int main(){
46char line[5];
47while(gets(line)){
48 x1=line[0]-'a',y1=line[1]-'1',x2=line[3]-'a',y2=line[4]-'1';
49 memset(visited,false,sizeof(visited));
50 k.x=x1,k.y=y1,k.g=k.step=0,k.h=Heuristic(k),k.f=k.g+k.h;
51while(!que.empty()) que.pop();
52 que.push(k);
53 Astar();
54 printf("To get from %c%c to %c%c takes %d knight moves.\n",line[0],line[1],line[3],line[4],ans);
55 }
56return0;
57}
58

6. 快速排序演算法的示例代碼

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespacetest{classQuickSort{staticvoidMain(string[]args){int[]array={49,38,65,97,76,13,27};sort(array,0,array.Length-1);Console.ReadLine();}/**一次排序單元,完成此方法,key左邊都比key小,key右邊都比key大。**@paramarray排序數組**@paramlow排序起始位置**@paramhigh排序結束位置**@return單元排序後的數組*/privatestaticintsortUnit(int[]array,intlow,inthigh){intkey=array[low];while(low<high){/*從後向前搜索比key小的值*/while(array[high]>=key&&high>low)--high;/*比key小的放左邊*/array[low]=array[high];/*從前向後搜索比key大的值,比key大的放右邊*/while(array[low]<=key&&high>low)++low;/*比key大的放右邊*/array[high]=array[low];}/*左邊都比key小,右邊都比key大。//將key放在游標當前位置。//此時low等於high*/array[low]=key;foreach(intiinarray){Console.Write({0} ,i);}Console.WriteLine();returnhigh;}/**快速排序*@paramarry*@return*/publicstaticvoidsort(int[]array,intlow,inthigh){if(low>=high)return;/*完成一次單元排序*/intindex=sortUnit(array,low,high);/*對左邊單元進行排序*/sort(array,low,index-1);/*對右邊單元進行排序*/sort(array,index+1,high);}}}運行結果:27 38 13 49 76 97 65
13 27 38 49 76 97 6513 27 38 49 65 76 97
快速排序就是遞歸調用此過程——在以49為中點分割這個數據序列,分別對前面一部分和後面一部分進行類似的快速排序,從而完成全部數據序列的快速排序,最後把此數據序列變成一個有序的序列,根據這種思想對於上述數組A的快速排序的全過程如圖6所示:
初始狀態 {49 38 65 97 76 13 27} 進行一次快速排序之後劃分為 {27 38 13} 49 {76 97 65} 分別對前後兩部分進行快速排序{27 38 13} 經第三步和第四步交換後變成 {13 27 38} 完成排序。{76 97 65} 經第三步和第四步交換後變成 {65 76 97} 完成排序。圖示 快速排序的最壞情況基於每次劃分對主元的選擇。基本的快速排序選取第一個元素作為主元。這樣在數組已經有序的情況下,每次劃分將得到最壞的結果。一種比較常見的優化方法是隨機化演算法,即隨機選取一個元素作為主元。這種情況下雖然最壞情況仍然是O(n^2),但最壞情況不再依賴於輸入數據,而是由於隨機函數取值不佳。實際上,隨機化快速排序得到理論最壞情況的可能性僅為1/(2^n)。所以隨機化快速排序可以對於絕大多數輸入數據達到O(nlogn)的期望時間復雜度。一位前輩做出了一個精闢的總結:「隨機化快速排序可以滿足一個人一輩子的人品需求。」
隨機化快速排序的唯一缺點在於,一旦輸入數據中有很多的相同數據,隨機化的效果將直接減弱。對於極限情況,即對於n個相同的數排序,隨機化快速排序的時間復雜度將毫無疑問的降低到O(n^2)。解決方法是用一種方法進行掃描,使沒有交換的情況下主元保留在原位置。 QUICKSORT(A,p,r)
1if p<r
2then q ←PARTITION(A,p,r)
3QUICKSORT(A,p,q-1)
4QUICKSORT(A,q+1,r)
為排序一個完整的數組A,最初的調用是QUICKSORT(A,1,length[A])。
快速排序演算法的關鍵是PARTITION過程,它對子數組A[p..r]進行就地重排:
PARTITION(A,p,r)
1x←A[r]
2i←p-1
3for j←p to r-1
4do if A[j]≤x
5then i←i+1
6exchange A[i]←→A[j]
7exchange A[i+1]←→A[r]
8return i+1 對PARTITION和QUICKSORT所作的改動比較小。在新的劃分過程中,我們在真正進行劃分之前實現交換:
(其中PARTITION過程同快速排序偽代碼(非隨機))
RANDOMIZED-PARTITION(A,p,r)
1i← RANDOM(p,r)
2exchange A[r]←→A[i]
3return PARTITION(A,p,r)
新的快速排序過程不再調用PARTITION,而是調用RANDOMIZED-PARTITION。
RANDOMIZED-QUICKSORT(A,p,r)
1if p<r
2then q← RANDOMIZED-PARTITION(A,p,r)
3RANDOMIZED-QUICKSORT(A,p,q-1)
4RANDOMIZED-QUICKSORT(A,q+1,r) 這里為方便起見,我們假設演算法Quick_Sort的范圍閾值為1(即一直將線性表分解到只剩一個元素),這對該演算法復雜性的分析沒有本質的影響。
我們先分析函數partition的性能,該函數對於確定的輸入復雜性是確定的。觀察該函數,我們發現,對於有n個元素的確定輸入L[p..r],該函數運行時間顯然為θ(n)。
最壞情況
無論適用哪一種方法來選擇pivot,由於我們不知道各個元素間的相對大小關系(若知道就已經排好序了),所以我們無法確定pivot的選擇對劃分造成的影響。因此對各種pivot選擇法而言,最壞情況和最好情況都是相同的。
我們從直覺上可以判斷出最壞情況發生在每次劃分過程產生的兩個區間分別包含n-1個元素和1個元素的時候(設輸入的表有n個元素)。下面我們暫時認為該猜測正確,在後文我們再詳細證明該猜測。
對於有n個元素的表L[p..r],由於函數Partition的計算時間為θ(n),所以快速排序在序壞情況下的復雜性有遞歸式如下:
T(1)=θ(1),T(n)=T(n-1)+T(1)+θ(n) (1)
用迭代法可以解出上式的解為T(n)=θ(n2)。
這個最壞情況運行時間與插入排序是一樣的。
下面我們來證明這種每次劃分過程產生的兩個區間分別包含n-1個元素和1個元素的情況就是最壞情況。
設T(n)是過程Quick_Sort作用於規模為n的輸入上的最壞情況的時間,則
T(n)=max(T(q)+T(n-q))+θ(n),其中1≤q≤n-1 (2)
我們假設對於任何k<n,總有T(k)≤ck,其中c為常數;顯然當k=1時是成立的。
將歸納假設代入(2),得到:
T(n)≤max(cq2+c(n-q)2)+θ(n)=c*max(q2+(n-q)2)+θ(n)
因為在[1,n-1]上q2+(n-q)2關於q遞減,所以當q=1時q2+(n-q)2有最大值n2-2(n-1)。於是有:
T(n)≤cn2-2c(n-1)+θ(n)≤cn2
只要c足夠大,上面的第二個小於等於號就可以成立。於是對於所有的n都有T(n)≤cn。
這樣,排序演算法的最壞情況運行時間為θ(n2),且最壞情況發生在每次劃分過程產生的兩個區間分別包含n-1個元素和1個元素的時候。
時間復雜度為o(n2)。
最好情況
如果每次劃分過程產生的區間大小都為n/2,則快速排序法運行就快得多了。這時有:
T(n)=2T(n/2)+θ(n),T(1)=θ(1) (3)
解得:T(n)=θ(nlogn)
快速排序法最佳情況下執行過程的遞歸樹如下圖所示,圖中lgn表示以10為底的對數,而本文中用logn表示以2為底的對數.
由於快速排序法也是基於比較的排序法,其運行時間為Ω(nlogn),所以如果每次劃分過程產生的區間大小都為n/2,則運行時間θ(nlogn)就是最好情況運行時間。
但是,是否一定要每次平均劃分才能達到最好情況呢?要理解這一點就必須理解對稱性是如何在描述運行時間的遞歸式中反映的。我們假設每次劃分過程都產生9:1的劃分,乍一看該劃分很不對稱。我們可以得到遞歸式:
T(n)=T(n/10)+T(9n/10)+θ(n),T(1)=θ(1) (4)
請注意樹的每一層都有代價n,直到在深度log10n=θ(logn)處達到邊界條件,以後各層代價至多為n。遞歸於深度log10/9n=θ(logn)處結束。這樣,快速排序的總時間代價為T(n)=θ(nlogn),從漸進意義上看就和劃分是在中間進行的一樣。事實上,即使是99:1的劃分時間代價也為θ(nlogn)。其原因在於,任何一種按常數比例進行劃分所產生的遞歸樹的深度都為θ(nlogn),其中每一層的代價為O(n),因而不管常數比例是什麼,總的運行時間都為θ(nlogn),只不過其中隱含的常數因子有所不同。(關於演算法復雜性的漸進階,請參閱演算法的復雜性)
平均情況
快速排序的平均運行時間為θ(nlogn)。
我們對平均情況下的性能作直覺上的分析。
要想對快速排序的平均情況有個較為清楚的概念,我們就要對遇到的各種輸入作個假設。通常都假設輸入數據的所有排列都是等可能的。後文中我們要討論這個假設。
當我們對一個隨機的輸入數組應用快速排序時,要想在每一層上都有同樣的劃分是不太可能的。我們所能期望的是某些劃分較對稱,另一些則很不對稱。事實上,我們可以證明,如果選擇L[p..r]的第一個元素作為支點元素,Partition所產生的劃分80%以上都比9:1更對稱,而另20%則比9:1差,這里證明從略。
平均情況下,Partition產生的劃分中既有「好的」,又有「差的」。這時,與Partition執行過程對應的遞歸樹中,好、差劃分是隨機地分布在樹的各層上的。為與我們的直覺相一致,假設好、差劃分交替出現在樹的各層上,且好的劃分是最佳情況劃分,而差的劃分是最壞情況下的劃分。在根節點處,劃分的代價為n,劃分出來的兩個子表的大小為n-1和1,即最壞情況。在根的下一層,大小為n-1的子表按最佳情況劃分成大小各為(n-1)/2的兩個子表。這兒我們假設含1個元素的子表的邊界條件代價為1。
在一個差的劃分後接一個好的劃分後,產生出三個子表,大小各為1,(n-1)/2和(n-1)/2,代價共為2n-1=θ(n)。一層劃分就產生出大小為(n-1)/2+1和(n-1)/2的兩個子表,代價為n=θ(n)。這種劃分差不多是完全對稱的,比9:1的劃分要好。從直覺上看,差的劃分的代價θ(n)可被吸收到好的劃分的代價θ(n)中去,結果是一個好的劃分。這樣,當好、差劃分交替分布劃分都是好的一樣:仍是θ(nlogn),但θ記號中隱含的常數因子要略大一些。關於平均情況的嚴格分析將在後文給出。
在前文從直覺上探討快速排序的平均性態過程中,我們已假定輸入數據的所有排列都是等可能的。如果輸入的分布滿足這個假設時,快速排序是對足夠大的輸入的理想選擇。但在實際應用中,這個假設就不會總是成立。
解決的方法是,利用隨機化策略,能夠克服分布的等可能性假設所帶來的問題。
一種隨機化策略是:與對輸入的分布作「假設」不同的是對輸入的分布作「規定」。具體地說,在排序輸入的線性表前,對其元素加以隨機排列,以強制的方法使每種排列滿足等可能性。事實上,我們可以找到一個能在O(n)時間內對含n個元素的數組加以隨機排列的演算法。這種修改不改變演算法的最壞情況運行時間,但它卻使得運行時間能夠獨立於輸入數據已排序的情況。
另一種隨機化策略是:利用前文介紹的選擇支點元素pivot的第四種方法,即隨機地在L[p..r]中選擇一個元素作為支點元素pivot。實際應用中通常採用這種方法。
快速排序的隨機化版本有一個和其他隨機化演算法一樣的有趣性質:沒有一個特別的輸入會導致最壞情況性態。這種演算法的最壞情況性態是由隨機數產生器決定的。你即使有意給出一個壞的輸入也沒用,因為隨機化排列會使得輸入數據的次序對演算法不產生影響。只有在隨機數產生器給出了一個很不巧的排列時,隨機化演算法的最壞情況性態才會出現。事實上可以證明幾乎所有的排列都可使快速排序接近平均情況性態,只有非常少的幾個排列才會導致演算法的近最壞情況性態。
一般來說,當一個演算法可按多條路子做下去,但又很難決定哪一條保證是好的選擇時,隨機化策略是很有用的。如果大部分選擇都是好的,則隨機地選一個就行了。通常,一個演算法在其執行過程中要做很多選擇。如果一個好的選擇的獲益大於壞的選擇的代價,那麼隨機地做一個選擇就能得到一個很有效的演算法。我們在前文已經了解到,對快速排序來說,一組好壞相雜的劃分仍能產生很好的運行時間 。因此我們可以認為該演算法的隨機化版本也能具有較好的性態。

7. Floyd演算法的參考代碼

function Floyd(w,router_direction,MAX)
%w為此圖的距離矩陣
%router_direction為路由類型:0為前向路由;非0為回溯路由
%MAX是數據輸入時的∞的實際值
len=length(w);
flag=zeros(1,len);
%根據路由類型初始化路由表
R=zeros(len,len);
for i=1:len
if router_direction==0%前向路由
R(:,i)=ones(len,1)*i;
else %回溯路由
R(i,:)=ones(len,1)*i;
end
R(i,i)=0;
end
disp('');
disp('w(0)');
dispit(w,0);
disp('R(0)');
dispit(R,1);
%處理端點有權的問題
for i=1:len
tmp=w(i,i)/2;
if tmp~=0
w(i,:)=w(i,:)+tmp;
w(:,i)=w(:,i)+tmp;
flag(i)=1;
w(i,i)=0;
end
end
%Floyd演算法具體實現過程
for i=1:len
for j=1:len
if j==i || w(j,i)==MAX
continue;
end
for k=1:len
if k==i || w(j,i)==MAX
continue;
end
if w(j,i)+w(i,k)<w(j,k) %Floyd演算法核心代碼
w(j,k)=w(j,i)+w(i,k);
if router_direction==0%前向路由
R(j,k)=R(j,i);
else %回溯路由
R(j,k)=R(i,k);
end
end
end
end
%顯示每次的計算結果
disp(['w(',num2str(i),')'])
dispit(w,0);
disp(['R(',num2str(i),')'])
dispit(R,1);
end
%中心和中點的確定
[Center,index]=min(max(w'));
disp(['中心是V',num2str(index)]);
[Middle,index]=min(sum(w'));
disp(['中點是V',num2str(index)]);
end
function dispit(x,flag)
%x:需要顯示的矩陣
%flag:為0時表示顯示w矩陣,非0時表示顯示R矩陣
len=length(x);
s=[];
for j=1:len
if flag==0
s=[s sprintf('%5.2f ',x(j,:))];
else
s=[s sprintf('%d ',x(j,:))];
end
s=[s sprintf(' ')];
end
disp(s);
disp('---------------------------------------------------');
end
% 選擇後按Ctrl+t取消注釋號%
%
% 示例:
% a=[
% 0,100,100,1.2,9.2,100,0.5;
% 100,0,100,5,100,3.1,2;
% 100,100,0,100,100,4,1.5;
% 1.2,5,100,0,6.7,100,100;
% 9.2,100,100,6.7,0,15.6,100;
% 100,3.1,4,100,15.6,0,100;
% 0.5,2,1.5,100,100,100,0
% ];
%
% b=[
% 0,9.2,1.1,3.5,100,100;
% 1.3,0,4.7,100,7.2,100;
% 2.5,100,0,100,1.8,100;
% 100,100,5.3,0,2.4,7.5;
% 100,6.4,2.2,8.9,0,5.1;
% 7.7,100,2.7,100,2.1,0
% ];
%
% Floyd(a,1,100)
% Floyd(b,1,100) program floyd;
var
st,en,f:integer;
k,n,i,j,x:integer;
a:array[1..10,1..10] of integer;
path:array[1..10,1..10] of integer;
begin
readln(n);
for i:=1 to n do
begin
for j:=1 to n do
begin
read(k);
if k<>0 then
a[i,j]:=k
else
a[i,j]:=maxint;
path[i,j]:=j;
end;
readln;
end;
for x:=1 to n do
for i:=1 to n do
for j:=1 to n do
if a[i,j]>a[i,x]+a[x,j] then
begin
a[i,j]:=a[i,x]+a[x,j];
path[i,j]:=path[i,x];
end;
readln(st,en);
writeln(a[st,en]);
f:=st;
while f<> en do
begin
write(f);
write('-->');
f:=path[f,en];
end;
writeln(en);
end. //以無向圖G為入口,得出任意兩點之間的路徑長度length[i][j],路徑path[i][j][k],//途中無連接得點距離用0表示,點自身也用0表示publicclassFLOYD{int[][]length=null;//任意兩點之間路徑長度int[][][]path=null;//任意兩點之間的路徑publicFLOYD(int[][]G){intMAX=100;introw=G.length;//圖G的行數int[][]spot=newint[row][row];//定義任意兩點之間經過的點int[]onePath=newint[row];//記錄一條路徑length=newint[row][row];path=newint[row][row][];for(inti=0;i<row;i++)//處理圖兩點之間的路徑for(intj=0;j<row;j++){if(G[i][j]==0)G[i][j]=MAX;//沒有路徑的兩個點之間的路徑為默認最大if(i==j)G[i][j]=0;//本身的路徑長度為0}for(inti=0;i<row;i++)//初始化為任意兩點之間沒有路徑for(intj=0;j<row;j++)spot[i][j]=-1;for(inti=0;i<row;i++)//假設任意兩點之間的沒有路徑onePath[i]=-1;for(intv=0;v<row;++v)for(intw=0;w<row;++w)length[v][w]=G[v][w];for(intu=0;u<row;++u)for(intv=0;v<row;++v)for(intw=0;w<row;++w)if(length[v][w]>length[v][u]+length[u][w]){length[v][w]=length[v][u]+length[u][w];//如果存在更短路徑則取更短路徑spot[v][w]=u;//把經過的點加入}for(inti=0;i<row;i++){//求出所有的路徑int[]point=newint[1];for(intj=0;j<row;j++){point[0]=0;onePath[point[0]++]=i;outputPath(spot,i,j,onePath,point);path[i][j]=newint[point[0]];for(ints=0;s<point[0];s++)path[i][j][s]=onePath[s];}}}voidoutputPath(int[][]spot,inti,intj,int[]onePath,int[]point){//輸出i//到j//的路徑的實際代碼,point[]記錄一條路徑的長度if(i==j)return;if(spot[i][j]==-1)onePath[point[0]++]=j;//System.out.print(+j+);else{outputPath(spot,i,spot[i][j],onePath,point);outputPath(spot,spot[i][j],j,onePath,point);}}publicstaticvoidmain(String[]args){intdata[][]={{0,27,44,17,11,27,42,0,0,0,20,25,21,21,18,27,0},//x1{27,0,31,27,49,0,0,0,0,0,0,0,52,21,41,0,0},//1{44,31,0,19,0,27,32,0,0,0,47,0,0,0,32,0,0},//2{17,27,19,0,14,0,0,0,0,0,30,0,0,0,31,0,0},//3{11,49,0,14,0,13,20,0,0,28,15,0,0,0,15,25,30},//4{27,0,27,0,13,0,9,21,0,26,26,0,0,0,28,29,0},//5{42,0,32,0,20,9,0,13,0,32,0,0,0,0,0,33,0},//6{0,0,0,0,0,21,13,0,19,0,0,0,0,0,0,0,0},//7{0,0,0,0,0,0,0,19,0,11,20,0,0,0,0,33,21},//8{0,0,0,0,28,26,32,0,11,0,10,20,0,0,29,14,13},//9{20,0,47,30,15,26,0,0,20,10,0,18,0,0,14,9,20},//10{25,0,0,0,0,0,0,0,0,20,18,0,23,0,0,14,0},//11{21,52,0,0,0,0,0,0,0,0,0,23,0,27,22,0,0},//12{21,21,0,0,0,0,0,0,0,0,0,0,27,0,0,0,0},//13{18,41,32,31,15,28,0,0,0,29,14,0,22,0,0,11,0},//14{27,0,0,0,25,29,33,0,33,14,9,14,0,0,11,0,9},//15{0,0,0,0,30,0,0,0,21,13,20,0,0,0,0,9,0}//16};for(inti=0;i<data.length;i++)for(intj=i;j<data.length;j++)if(data[i][j]!=data[j][i])return;FLOYDtest=newFLOYD(data);for(inti=0;i<data.length;i++)for(intj=i;j<data[i].length;j++){System.out.println();System.out.print(From+i+to+j+pathis:);for(intk=0;k<test.path[i][j].length;k++)System.out.print(test.path[i][j][k]+);System.out.println();System.out.println(From+i+to+j+length:+test.length[i][j]);}}}

熱點內容
反編譯軟體id 發布:2024-04-20 10:29:49 瀏覽:44
視頻太長怎麼壓縮發微信 發布:2024-04-20 10:00:14 瀏覽:384
顯卡怎麼保存配置 發布:2024-04-20 09:28:52 瀏覽:596
校園交易網站源碼 發布:2024-04-20 09:18:54 瀏覽:701
江蘇北斗授時伺服器ip雲空間 發布:2024-04-20 08:53:50 瀏覽:931
dedecms批量上傳圖片 發布:2024-04-20 08:42:11 瀏覽:966
酷q如何編譯 發布:2024-04-20 08:41:27 瀏覽:79
安卓手機數字人民幣怎麼下載 發布:2024-04-20 08:38:21 瀏覽:114
access如何配置資料庫 發布:2024-04-20 08:37:35 瀏覽:504
手寫輸入演算法 發布:2024-04-20 08:29:31 瀏覽:258