導航:首頁 > 源碼編譯 > sort演算法動畫

sort演算法動畫

發布時間:2022-07-27 11:22:39

1. java中Arrays.sort使用的是什麼演算法

Arrays.sort()
先來看看Arrays.sort();,一點進這個方法會看到是這樣子的
publicstaticvoidsort(int[]a){
DualPivotQuicksort.sort(a,0,a.length-1,null,0,0);
}123
果然沒這么簡單,DualPivotQuicksort翻譯過來就是雙軸快速排序,關於雙軸排序可以去這里http://www.cnblogs.com/nullzx/p/5880191.html看看。那再次點進去,可以發現有這么一段代碼
if(right-left<QUICKSORT_THRESHOLD){
sort(a,left,right,true);
return;
}1234
可以發現如果數組的長度小於QUICKSORT_THRESHOLD的話就會使用這個雙軸快速排序,而這個值是286。
那如果大於286呢,它就會堅持數組的連續升序和連續降序性好不好,如果好的話就用歸並排序,不好的話就用快速排序,看下面這段注釋就可以看出
*Thearrayisnothighlystructured,
*.
123
那現在再回到上面的決定用雙軸快速排序的方法上,再點進去,發現又會多一條判斷
//Useinsertionsortontinyarrays
if(length<INSERTION_SORT_THRESHOLD)
123
即如果數組長度小於INSERTION_SORT_THRESHOLD(值為47)的話,那麼就會用插入排序了,不然再用雙軸快速排序。
所以總結一下Arrays.sort()方法,如果數組長度大於等於286且連續性好的話,就用歸並排序,如果大於等於286且連續性不好的話就用雙軸快速排序。如果長度小於286且大於等於47的話就用雙軸快速排序,如果長度小於47的話就用插入排序。真是有夠繞的~

2. 用Javascript寫排序演算法的動畫演示

1.讓JavaScript暫停下來,慢下來。
JavaScript排序是很快的,要我們肉眼能看到它的實現過程,我首先想到的是讓排序慢下來。 排序的每一個循環都讓它停300ms然後再繼續進行。 怎麼樣才能停下來呢。查了一下JavaScript貌似沒有sleep()這樣的函數。暫停做不到,但是可以想辦法讓實現跟暫停差不多的效果。比如在循環里做一些無關的事情 。
首先嘗試了讓while(true)來一直執行一個空操作。執行一段時間再回到排序邏輯。代碼大致是這樣:
for (var i = 0; i < 3; i++) {
document.writeln(i); //DOM操作
var now = new Date().getTime();
while(new Date().getTime() - now < 3000){}
}

慢是慢下來了。不過太耗資源,排序進行過程中dom並不會有任何改變,直到排序結束, DOM會變成排序好之後的樣子。 但是如果設置斷點一步步執行的時候 又可以看到一步步的排序變化。估計是因為這個操作太耗資源導致瀏覽器下達了一個DOM操作的命令但是一直騰不出資源來進行DOM操作。所以真正DOM操作的時候在js代碼執行結束之後。
所以讓JavaScript排序慢來來還是沒有實現。
另一種讓JavaScript暫停下來的思路:
寫這個文章的時候又想到一種方法來讓JavaScript停下來。 那就是AJAX的同步請求,以及超時操作。 也就是在要停下來的地方放一個AJAX請求,同步請求, 然後設置超時。超時的時間就是我們要暫停的時間。為了避免在到達超時請求之前服務 器就返回了我們的AJAX請求。可以在服務端運行類似 sleep()的程序 。從而保證AJAX不會返回。直接超時然後返回到我們的循環。不過這只是個設想。有興趣的可以去嘗試一下。
2.閉包和定時器。 這種思路不需要讓排序過程慢下來。而是使用閉包緩存排序過程中數組的變化。然後使用setTimeout來確定展示每一個數組狀態的順序。在排序循環中放入類似下面的代碼。
(function(){
var theArr = arr.slice();//當前數組狀態的備份
setTimeout(function(){
bubbleSortDom(theArr);//排序的DOM操作。
},500*timeCount);
timeCount++;//定時器的順序。
})();

不過後來發現這樣子寫的話代碼量會比較大,邏輯有修改的話要修改的地方會有點多。局限性很多,比如要實現排序動畫加快或減慢操作幾乎是很困難的。所以還要另想辦法。
3.緩存排序中的數組狀態。
也就是在排序過程中。將數組的每一輪循環的狀態保存到一個數組。然後再用這個數組依次將排序狀態保存下來。 只需要在排序中加入一句就行。
this.pushHis(arr.slice(),i-1,j,k,temp);

這樣就只需要一個setInterval()就可以了。並且可以很方便的實現動畫的加快與減慢。邏輯也比較好理解 。
問題二:如何實現JavaScript排序動畫的加快與減慢。
我們問題一使用的第三種方法。 得到一個保存了每一步排序狀態的數組arr。 然後我們可以使用一個setInterval()定時器一步步展現排序狀態。 如果要加快速度或減慢速度。就clearInterval(),修改定時器的執行間隔,重新setInterval(),從前一個定時器執行到數組中的位置開始執行。
問題三:對於使用遞歸實現的數組怎麼辦? 不是在原數組上進行操作的怎麼辦?
使用遞歸實現的排序。 可能並沒有在一個數組上進行操作,只是最後返回一個排序好的數組出來。那麼我們要如何獲得排序中的數組的完整狀態呢。
比如快速排序。
最開始不考慮動畫,我的實現是這樣的:
function quickSort(arr){
var len = arr.length,leftArr=[],rightArr=[],tag;
if(len<2){
return arr;
}
tag = arr[0];
for(i=1;i<len;i++){
if(arr[i]<=tag){
leftArr.push(arr[i])
}else{
rightArr.push(arr[i]);
}
}
return quickSort(leftArr).concat(tag,quickSort(rightArr));
}

然後為了考慮動畫,我改寫了它的邏輯,讓它在同一個數組上進行了實現。 其實是在遞歸的時候傳入了當前的的子數組在原數組中的起始位置。從而在原數組上進行了操作。
用了兩種方法來實現方式。在排序邏輯上略有不同。
第一種是先跟遠處的對比。遇到比自己小的放到自己前面去。循環序號+1。比自己大的放到當前排序子數組的最後面去,循環序號不變。直到排列完成。
這種方法的缺點是即使是一個有序數組。它也會重新排。
第二種方法是 除了標記位,再設置一個對比位。 遇到比自己小的,放到前面去,標記位的位置+1,標記位與對比位之間所有的往後面移動一個位置。
遇到比自己大的。標記位不變,對比位+1。
這種方法的缺點是對數組進行的操作太多。優點是對有序數組不會再排。
方式一:
function quickSort(arr,a,b,qArr){

var len = arr.length,leftArr=[],rightArr=[],tag,i,k,len_l,len_r,lb,ra,temp;
if(a == undefined && b == undefined){
a = 0; b= arr.length-1;//初始化起始位置。
}
if(qArr == undefined){
qArr = arr.slice();
}

if((len == 2 && arr[0] == arr[1])||len<2){
return arr;
}

tag = qArr[a];
for (i = 1; i < len;) {
if(qArr[a+i]<=tag){
leftArr.push(qArr[a+i]);
qArr[a+i-1] = qArr[a+i];
qArr[a+i] = tag;
k = a+i;
i++;
}else{
if(leftArr.length+rightArr.length == len-1){
break;
}
temp = qArr[a+i];
qArr[a+i] = qArr[b-rightArr.length];
qArr[b-rightArr.length] = temp;
rightArr.push(temp);
k = a+i-1;
}
this.pushHis(qArr.slice(),a,b,k);
}

len_l = leftArr.length;
len_r = rightArr.length;
if(len_l== 0){
lb = a;
}else{
lb = a+len_l -1;
this.sort(leftArr,a,lb,qArr);
}

if(len_r == 0){
ra = b;
}else{
ra = b + 1 - len_r;
this.sort(rightArr,ra,b,qArr)
}
return qArr
}

方式二:
function quickSort2(arr,a,b,qArr){
var len = arr.length,leftArr=[],rightArr=[],tag,i,j,k,temp,len_l,len_r,lb,ra;
if(a == undefined && b == undefined){
a = 0; b= arr.length-1;//初始化起始位置。
}
if(qArr == undefined){
qArr = arr.slice();
}
if(len<2){
return arr;
}
if(len == 2 && arr[0] == arr[1]){
return arr;
}
tag = qArr[a];
for (i = 1,k = 0; i < len;) {
if(qArr[a+i]>=tag){
rightArr.push(qArr[a+i]);
i++;
}else{
temp = qArr[a+i];
for(j = a+i;j>a+k;j--){
qArr[j] = qArr[j-1];
// this.pushHis(qArr.slice(),a,b,a+k);
}
qArr[a+k] = temp;
leftArr.push(temp);
k++;
i++;
}
this.pushHis(qArr.slice(),a,b,a+k,i-1);
}
len_l = leftArr.length;
len_r = rightArr.length;
if(len_l== 0){
lb = a;
}else{
lb = a+len_l -1;
this.sort(leftArr,a,lb,qArr);
}
if(len_r == 0){
ra = b;
}else{
ra = b + 1 - len_r;
this.sort(rightArr,ra,b,qArr)
}
return qArr;
}

具體的不同下面會有動畫演示。
問題四:動畫的流暢。
排序動畫的DOM操作是很多的很快的。這里我做的優化只是讓每一個排序步驟只涉及一個DOM操作。 全部由JavaScript拼接好,一次替換。類似下面的代碼。
效果圖:

主要實現了:
冒泡排序JavaScript動畫演示
插入排序JavaScript動畫演示
選擇排序JavaScript動畫演示
快速排序JavaScript動畫演示
歸並排序JavaScript動畫演示
希爾排序JavaScript動畫演示

3. 排序演算法的動態顯示 c++

演算法如下,採用責任鏈模式進行各類排序演算法的串接,當前已經實現選擇排序和插入排序。
代碼已經在VC中運行驗證,謝謝!
#include <iostream>

using namespace std;

//排序介面類,抽象類
class SortInterface
{
public:
virtual bool sort(int type, int array[], int len) = 0;
protected:
int m_Type;
virtual bool callNext(int type, int array[], int len)
{
return false;
};
};

//插入排序類
class InsertSort : public SortInterface
{
public:
bool sort(int type, int array[], int len)
{
if (type != m_Type)
{
return false;
}
insertSort(array, len);
return true;
}
InsertSort()
{
m_Type = 1;
}
private:
void insertSort(int array[], int len)
{
int i,j,k;
for(i = 1; i < len; i++)
{
for(j = 0; j < i; j++)
{
if (array[i] < array[j])
{
int temp = array[i];
for(k = i; k > j; k--)
array[k] = array[k - 1];
array[j] = temp;
}
}
}
}
};

//選擇排序類
class SelectSort : public SortInterface
{
public:
bool sort(int type, int array[], int len)
{
bool breturn = false;
if (type != m_Type)
{
return callNext(type, array, len);
}
selectSort(array, len);
return true;
}

SelectSort()
{
m_Type = 0;
}

protected:
bool callNext(int type, int array[], int len)
{
bool breturn = false;
SortInterface *nextSort = new InsertSort();
breturn = nextSort->sort(type, array, len);
delete nextSort;
return breturn;
}
private:
void selectSort(int array[], int len)
{
int i,j,pos = 0;
for(i = len - 1; i > 0; i--)
{
pos = 0;
for(j = 1; j <= i; j++)
{
if(array[pos] < array[j])
pos = j;
}

if (pos != i)
{
array[pos] = array[pos] + array[i];
array[i] = array[pos] - array[i];
array[pos] = array[pos] - array[i];
}
}
}
};

//排序類,採用責任鏈模式串接所有的排序方法,這樣僅需要新增當前最後一個
//排序演算法的callNext方法和新排序演算法類即可,需要注意type的遞增
class Sort {
public:
bool sort(int type, int array[], int len)
{
bool breturn = false;
SortInterface *firstSort = new SelectSort();
breturn = firstSort->sort(type, array, len);
delete firstSort;
return breturn;
}
void print(int array[], int len)
{
for(int i= 0; i < len; i++)
cout<<array[i];
cout<<endl;
}
};

void main()
{
int num, type;
int *array;
Sort *sortFunction;
cout<<"Input the amount of numbers(>0): ";
cin>>num;
if (num <= 0)
return;
array = new int[num];
cout<<"Input the numbers: "<<endl;
for(int i = 0; i < num; i++)
cin>>array[i];
cout<<"Input the sort type(0 or 1): ";
cin>>type;
sortFunction = new Sort();
if(sortFunction->sort(type,array,num))
{
sortFunction->print(array,num);
}
else
{
cout<<"Sort failed, your sort type maybe not be found."<<endl;
}
delete sortFunction;
delete []array;
}

4. linux sort命令 演算法

man sort中關於它的描述是
sort - sort lines of text files

所以,它默認是以文本排序的。
但是它又有其它參數
-b, --ignore-leading-blanks
ignore leading blanks
-d, --dictionary-order
consider only blanks and alphanumeric characters
-f, --ignore-case
fold lower case to upper case characters
-g, --general-numeric-sort
compare according to general numerical value
-i, --ignore-nonprinting
consider only printable characters
-M, --month-sort
compare (unknown) < 『JAN』 < ... < 『DEC』
-n, --numeric-sort
compare according to string numerical value
-r, --reverse
reverse the result of comparisons
可以忽略前置的空格、或指定順序字典、或忽略大小寫、或以正常的數字形式、或忽略不可列印字元、或以月份(包括英語的月份)、或以字元形式的數字、或以倒序形式排序。

5. sort如何排序自定義數據類型 - C / C++ -

比如你要排的數據類型是A,元素已放好在數組Array中,長為size
sort(Array,Array + size,cmp);

cmp是一個返回bool的函數,用於定義排序順序
bool cmp(A& a1,A& a2){
return a1.member > a2.member; //按member的順序從大到小排序

}

如果略去最後的cmp,sort演算法默認從小到大排序,但自定義的數據類型一定要重載大於號,小於號等比較運算符

6. 冒泡排序法和快速排序比較的演算法

打你屁股,這么簡單的問題都不認真研究一下。

冒泡排序是最慢的排序,時間復雜度是 O(n^2)。

快速排序是最快的排序。關於快速排序,我推薦你看看《代碼之美》第二章:我編寫過的最漂亮的代碼。作者所說的最漂亮,就是指效率最高的。

--------------------------------摘自《代碼之美》---------------

當我撰寫關於分治(divide-and-conquer)演算法的論文時,我發現C.A.R. Hoare的Quicksort演算法(「Quicksort」,Computer Journal 5)無疑是各種Quicksort演算法的鼻祖。這是一種解決基本問題的漂亮演算法,可以用優雅的代碼實現。我很喜歡這個演算法,但我總是無法弄明白演算法中最內層的循環。我曾經花兩天的時間來調試一個使用了這個循環的復雜程序,並且幾年以來,當我需要完成類似的任務時,我會很小心地復制這段代碼。雖然這段代碼能夠解決我所遇到的問題,但我卻並沒有真正地理解它。
我後來從Nico Lomuto那裡學到了一種優雅的劃分(partitioning)模式,並且最終編寫出了我能夠理解,甚至能夠證明的Quicksort演算法。William Strunk Jr.針對英語所提出的「良好的寫作風格即為簡練」這條經驗同樣適用於代碼的編寫,因此我遵循了他的建議,「省略不必要的字詞」(來自《The Elements of Style》一書)。我最終將大約40行左右的代碼縮減為十幾行的代碼。因此,如果要回答「你曾編寫過的最漂亮代碼是什麼?」這個問題,那麼我的答案就是:在我編寫的《Programming Pearls, Second Edition》(Addison-Wesley)一書中給出的Quichsort演算法。在示例2-1中給出了用C語言編寫的Quicksort函數。我們在接下來的章節中將進一步地研究和改善這個函數。
【示例】 2-1 Quicksort函數
void quicksort(int l, int u)
{ int i, m;
if (l >= u) return; 10
swap(l, randint(l, u));
m = l;
for (i = l+1; i <= u; i++)
if (x[i] < x[l])
swap(++m, i);
swap(l, m);
quicksort(l, m-1);
quicksort(m+1, u);
}
如果函數的調用形式是quicksort(0, n-1),那麼這段代碼將對一個全局數組x[n]進行排序。函數的兩個參數分別是將要進行排序的子數組的下標:l是較低的下標,而u是較高的下標。函數調用swap(i,j)將會交換x[i]與x[j]這兩個元素。第一次交換操作將會按照均勻分布的方式在l和u之間隨機地選擇一個劃分元素。
在《Programming Pearls》一書中包含了對Quicksort演算法的詳細推導以及正確性證明。在本章的剩餘內容中,我將假設讀者熟悉在《Programming Pearls》中所給出的Quicksort演算法以及在大多數初級演算法教科書中所給出的Quicksort演算法。
如果你把問題改為「在你編寫那些廣為應用的代碼中,哪一段代碼是最漂亮的?」我的答案還是Quicksort演算法。在我和M. D. McIlroy一起編寫的一篇文章("Engineering a sort function," Software-Practice and Experience, Vol. 23, No. 11)中指出了在原來Unix qsort函數中的一個嚴重的性能問題。隨後,我們開始用C語言編寫一個新排序函數庫,並且考慮了許多不同的演算法,包括合並排序(Merge Sort)和堆排序(Heap Sort)等演算法。在比較了Quicksort的幾種實現方案後,我們著手創建自己的Quicksort演算法。在這篇文章中描述了我們如何設計出一個比這個演算法的其他實現要更為清晰,速度更快以及更為健壯的新函數——部分原因是由於這個函數的代碼更為短小。Gordon Bell的名言被證明是正確的:「在計算機系統中,那些最廉價,速度最快以及最為可靠的組件是不存在的。」現在,這個函數已經被使用了10多年的時間,並且沒有出現任何故障。
考慮到通過縮減代碼量所得到的好處,我最後以第三種方式來問自己在本章之初提出的問題。「你沒有編寫過的最漂亮代碼是什麼?」。我如何使用非常少的代碼來實現大量的功能?答案還是和Quicksort有關,特別是對這個演算法的性能分析。我將在下一節給出詳細介紹。
2.2 事倍功半
Quicksort是一種優雅的演算法,這一點有助於對這個演算法進行細致的分析。大約在1980年左右,我與Tony Hoare曾經討論過Quicksort演算法的歷史。他告訴我,當他最初開發出Quicksort時,他認為這種演算法太簡單了,不值得發表,而且直到能夠分析出這種演算法的預期運行時間之後,他才寫出了經典的「Quicksoft」論文。
我們很容易看出,在最壞的情況下,Quicksort可能需要n2的時間來對數組元素進行排序。而在最優的情況下,它將選擇中值作為劃分元素,因此只需nlgn次的比較就可以完成對數組的排序。那麼,對於n個不同值的隨機數組來說,這個演算法平均將進行多少次比較?
Hoare對於這個問題的分析非常漂亮,但不幸的是,其中所使用的數學知識超出了大多數程序員的理解范圍。當我為本科生講授Quicksort演算法時,許多學生即使在費了很大的努力之後,還是無法理解其中的證明過程,這令我非常沮喪。下面,我們將從Hoare的程序開
11
始討論,並且最後將給出一個與他的證明很接近的分析。
我們的任務是對示例2-1中的Quicksort代碼進行修改,以分析在對元素值均不相同的數組進行排序時平均需要進行多少次比較。我們還將努力通過最短的代碼、最短運行時間以及最小存儲空間來得到最深的理解。
為了確定平均比較的次數,我們首先對程序進行修改以統計次數。因此,在內部循環進行比較之前,我們將增加變數comps的值(參見示例2-2)。
【示例2-2】 修改Quicksort的內部循環以統計比較次數。
for (i = l+1; i <= u; i++) {
comps++;
if (x[i] < x[l])
swap(++m, i);
}
如果用一個值n來運行程序,我們將會看到在程序的運行過程中總共進行了多少次比較。如果重復用n來運行程序,並且用統計的方法來分析結果,我們將得到Quicksort在對n個元素進行排序時平均使用了1.4 nlgn次的比較。
在理解程序的行為上,這是一種不錯的方法。通過十三行的代碼和一些實驗可以反應出許多問題。這里,我們引用作家Blaise Pascal和T. S. Eliot的話,「如果我有更多的時間,那麼我給你寫的信就會更短。」現在,我們有充足的時間,因此就讓我們來對代碼進行修改,並且努力編寫出更短(同時更好)的程序。
我們要做的事情就是提高這個演算法的速度,並且盡量增加統計的精確度以及對程序的理解。由於內部循環總是會執行u-l次比較,因此我們可以通過在循環外部增加一個簡單的操作來統計比較次數,這就可以使程序運行得更快一些。在示例2-3的Quicksort演算法中給出了這個修改。
【示例2-3】 Quicksort的內部循環,將遞增操作移到循環的外部
comps += u-l;
for (i = l+1; i <= u; i++)
if (x[i] < x[l])
swap(++m, i);
這個程序會對一個數組進行排序,同時統計比較的次數。不過,如果我們的目標只是統計比較的次數,那麼就不需要對數組進行實際地排序。在示例2-4中去掉了對元素進行排序的「實際操作」,而只是保留了程序中各種函數調用的「框架」。
【示例2-4】將Quicksort演算法的框架縮減為只進行統計
void quickcount(int l, int u)
{ int m;
if (l >= u) return;
m = randint(l, u);
comps += u-l;
quickcount(l, m-1);
quickcount(m+1, u);
}
12
這個程序能夠實現我們的需求,因為Quichsort在選擇劃分元素時採用的是「隨機」方式,並且我們假設所有的元素都是不相等的。現在,這個新程序的運行時間與n成正比,並且相對於示例2-3需要的存儲空間與n成正比來說,現在所需的存儲空間縮減為遞歸堆棧的大小,即存儲空間的平均大小與lgn成正比。
雖然在實際的程序中,數組的下標(l和u)是非常重要的,但在這個框架版本中並不重要。因此,我們可以用一個表示子數組大小的整數(n)來替代這兩個下標(參見示例2-5)
【示例2-5】 在Quicksort代碼框架中使用一個表示子數組大小的參數
void qc(int n)
{ int m;
if (n <= 1) return;
m = randint(1, n);
comps += n-1;
qc(m-1);
qc(n-m);
}
現在,我們可以很自然地把這個過程整理為一個統計比較次數的函數,這個函數將返回在隨機Quicksort演算法中的比較次數。在示例2-6中給出了這個函數。
【示例2-6】 將Quicksort框架實現為一個函數
int cc(int n)
{ int m;
if (n <= 1) return 0;
m = randint(1, n);
return n-1 + cc(m-1) + cc(n-m);
}
在示例2-4、示例2-5和示例2-6中解決的都是相同的基本問題,並且所需的都是相同的運行時間和存儲空間。在後面的每個示例都對這些函數的形式進行了改進,從而比這些函數更為清晰和簡潔。
在定義發明家的矛盾(inventor's paradox)(How To Solve It, Princeton University Press)時,George Póllya指出「計劃越宏大,成功的可能性就越大。」現在,我們就來研究在分析Quicksort時的矛盾。到目前為止,我們遇到的問題是,「當Quicksort對大小為n的數組進行一次排序時,需要進行多少次比較?」我們現在將對這個問題進行擴展,「對於大小為n的隨機數組來說,Quichsort演算法平均需要進行多少次的比較?」我們通過對示例2-6進行擴展以引出示例2-7。
【示例2-7】 偽碼:Quicksort的平均比較次數
float c(int n)
if (n <= 1) return 0
sum = 0
for (m = 1; m <= n; m++)
sum += n-1 + c(m-1) + c(n-m)
return sum/n
如果在輸入的數組中最多隻有一個元素,那麼Quichsort將不會進行比較,如示例2-6
13
中所示。對於更大的n,這段代碼將考慮每個劃分值m(從第一個元素到最後一個,每個都是等可能的)並且確定在這個元素的位置上進行劃分的運行開銷。然後,這段代碼將統計這些開銷的總和(這樣就遞歸地解決了一個大小為m-1的問題和一個大小為n-m的問題),然後將總和除以n得到平均值並返回這個結果。
如果我們能夠計算這個數值,那麼將使我們實驗的功能更加強大。我們現在無需對一個n值運行多次來估計平均值,而只需一個簡單的實驗便可以得到真實的平均值。不幸的是,實現這個功能是要付出代價的:這個程序的運行時間正比於3n(如果是自行參考(self-referential)的,那麼用本章中給出的技術來分析運行時間將是一個很有趣的練習)。
示例2-7中的代碼需要一定的時間開銷,因為它重復計算了中間結果。當在程序中出現這種情況時,我們通常會使用動態編程來存儲中間結果,從而避免重復計算。因此,我們將定義一個表t[N+1],其中在t[n]中存儲c[n],並且按照升序來計算它的值。我們將用N來表示n的最大值,也就是進行排序的數組的大小。在示例2-8中給出了修改後的代碼。
【示例2-8】 在Quicksort中使用動態編程來計算
t[0] = 0
for (n = 1; n <= N; n++)
sum = 0
for (i = 1; i <= n; i++)
sum += n-1 + t[i-1] + t[n-i]
t[n] = sum/n
這個程序只對示例2-7進行了細微的修改,即用t[n]來替換c(n)。它的運行時間將正比於N2,並且所需的存儲空間正比於N。這個程序的優點之一就是:在程序執行結束時,數組t中將包含數組中從元素0到元素N的真實平均值(而不是樣本均值的估計)。我們可以對這些值進行分析,從而生成在Quichsort演算法中統計比較次數的計算公式。
我們現在來對程序做進一步的簡化。第一步就是把n-1移到循環的外面,如示例2-9所示。
【示例2-9】 在Quicksort中把代碼移到循環外面來計算
t[0] = 0
for (n = 1; n <= N; n++)
sum = 0
for (i = 1; i <= n; i++)
sum += t[i-1] + t[n-i]
t[n] = n-1 + sum/n
現在將利用對稱性來對循環做進一步的調整。例如,當n為4時,內部循環計算總和為:
t[0]+t[3] + t[1]+t[2] + t[2]+t[1] + t[3]+t[0]
在上面這些組對中,第一個元素增加而第二個元素減少。因此,我們可以把總和改寫為:
2 * (t[0] + t[1] + t[2] + t[3])
我們可以利用這種對稱性來得到示例2-10中的Quicksort。
【示例2-10】 在Quichsort中利用了對稱性來計算
t[0] = 0
14
for (n = 1; n <= N; n++)
sum = 0
for (i = 0; i < n; i++)
sum += 2 * t[i]
t[n] = n-1 + sum/n
然而,在這段代碼的運行時間中同樣存在著浪費,因為它重復地計算了相同的總和。此時,我們不是把前面所有的元素加在一起,而是在循環外部初始化總和並且加上下一個元素,如示例2-11所示。
【示例2-11】 在Quicksort中刪除了內部循環來計算
sum = 0; t[0] = 0
for (n = 1; n <= N; n++)
sum += 2*t[n-1]
t[n] = n-1 + sum/n
這個小程序確實很有用。程序的運行時間與N成正比,對於每個從1到N的整數,程序將生成一張Quicksort的估計運行時間表。
我們可以很容易地把示例2-11用表格來實現,其中的值可以立即用於進一步的分析。在2-1給出了最初的結果行。
表2-1 示例2-11中實現的表格輸出
N Sum t[n]
0 0 0
1 0 0
2 0 1
3 2 2.667
4 7.333 4.833
5 17 7.4
6 31.8 10.3
7 52.4 13.486
8 79.371 16.921
這張表中的第一行數字是用代碼中的三個常量來進行初始化的。下一行(輸出的第三行)的數值是通過以下公式來計算的:
A3 = A2+1 B3 = B2 + 2*C2 C3 = A2-1 + B3/A3
把這些(相應的)公式記錄下來就使得這張表格變得完整了。這張表格是「我曾經編寫的最漂亮代碼」的很好的證據,即使用少量的代碼完成大量的工作。
但是,如果我們不需要所有的值,那麼情況將會是什麼樣?如果我們更希望通過這種來方式分析一部分數值(例如,在20到232之間所有2的指數值)呢?雖然在示例2-11中構建了完整的表格t,但它只需要使用表格中的最新值。因此,我們可以用變數t的定長空間來替代table t[]的線性空間,如示例2-12所示。
【示例2-12】 Quicksoft 計算——最終版本
sum = 0; t = 0
15
for (n = 1; n <= N; n++)
sum += 2*t
t = n-1 + sum/n
然後,我們可以插入一行代碼來測試n的適應性,並且在必要時輸出這些結果。
這個程序是我們漫長學習旅途的終點。通過本章所採用的方式,我們可以證明Alan Perlis的經驗是正確的:「簡單性並不是在復雜性之前,而是在復雜性之後」 ("Epigrams on Programming," Sigplan Notices, Vol. 17, Issue 9)。

7. 題目:設計和實現描述任意一個排序演算法(快速排序、冒泡排序、選擇排序等)的動畫。

動畫?

8. 集合類的sort方法採用的什麼排序演算法

諸如List<T>等泛型集合類,直接提供了sort()方法用於將集合中的元素進行排序。
但是,其前提是集合中存放的是可直接排序的基本類型,如List<int>, List<double>,如果
我們定義了一個自定義類型 Class MyClass,並創建一個自定義類型的集合如List<MyClass>,
那麼無參的sort()方法就不可用了,因為不知道如何排序了。這時就需要藉助:
IComparer 和 IComparable
首先,我們來看一下c#泛型List提供的Sort方法:

泛型List類的Sort方法有四種形式,分別是
1,不帶有任何參數的Sort方法----Sort();
2,帶有比較器參數的Sort方法 ----Sort(IComparer<T>)
3,帶有比較代理方法參數的Sort方法----Sort(Comparison<(Of <(T>)>))
4,帶有比較器參數,可以指定排序范圍的Sort方法----Sort(Int32, Int32 IComparer(T))

【解析:】第一種方法

使用這種方法不是對List中的任何元素對象都可以進行排序,List中的元素對象必須繼承IComparable介面,並且要實現IComparable介面中的CompareTo()方法,在CompareTo()方法中要自己實現對象的比較規則。

例如,Int32和Double都是實現了IComparable介面並重載了CompareTo方法的結構。(註:int和double都是Int32和Double的別名(alias))

【解析:】第二種方法

2,帶有比較器參數的Sort方法 ----Sort(IComparer<T>),

1)創建一個額外的比較器類:其實就相當於將排序功能中的比較操作,留個使用者來完成。這個比較操作必須在實現了IComparer介面的自定義比較類中完成;如:

class myComparer:IComparer<MyClass>

2)制定比較規則實現比較方法:因為介面中有一個用於比較的重載函數Compare,所在在比較器類中我們必須實現它,完成自己希望的比較。所謂自己希望的比較就是說自己實現自定義對象的比較規則,例如你知道自定義類MyClass中哪個屬性適合用來排序,那麼就選擇這個屬性作為整個自定義類對象的排序屬性,如該類中有年齡,學號,入學日期等屬性,你可以選擇年齡屬性作為排序屬性。如:

public class myComparer:IComparer<MyClass>
{
//實現按年齡升序排列
public int Compare(MyClass x, MyClass y)
{
return (x.age.CompareTo(y.age)); //age代表年齡屬性是整型,即其已支持CompareTo方法
}
}

3)使用比較器的排序方法調用:然後,在自定義類型的集合如List<MyClass> myList,上就可以進行sort排序了,如

myList.Sort(new myComparer());

【解析:】第三種方法
3,帶有比較代理方法參數的Sort方法----Sort(Comparison<(Of <(T>)>))
Comparison<(Of

<(T>)>是一種泛型委託。所以,需要編寫一個對象排序比較的方法,對List中的元素對象沒有特殊的要求,但在比較方法中需要實現
對象比較規則,這個方法實現後,就可以把這方名字作為參數委託給List的Sort方法,Sort方法在排序時會執行這個方法對List中的對象進行比較
需要編寫一個對象排序比較的方法,對List中的元素對象沒有特殊的要求,但在比較方法中需要實現對象比較規則,這個方法實現後,就可以把這方名字作為參
數委託給List的Sort方法,Sort方法在排序時會執行這個方法對List中的對象進行比較

【解析:】第四種方法
4,帶有比較器參數,可以指定排序范圍的Sort方法----Sort(Int32, Int32 IComparer(T))
對於第四排序方法,實際是第二種比較器排序的一個擴展,在指定排序比較器的同時,指定排序范圍,即List中准備排序的開始元素索引和結束元素索引

閱讀全文

與sort演算法動畫相關的資料

熱點內容
pgp基於什麼體系加密 瀏覽:633
python合法賦值語句格式 瀏覽:709
程序員數學線性代數 瀏覽:622
看幀率app如何使用 瀏覽:523
從DHC伺服器租用IP地址 瀏覽:473
編譯怎麼學 瀏覽:329
數碼管顯示0到9plc編程 瀏覽:665
伺服器是為什麼服務的 瀏覽:765
java定義數據類型 瀏覽:874
安卓pdf手寫 瀏覽:427
什麼是app開發者 瀏覽:284
android鬧鍾重啟 瀏覽:101
程序員失職 瀏覽:520
在雲伺服器怎麼改密碼 瀏覽:588
伺服器pb什麼意思 瀏覽:942
51駕駛員的是什麼app 瀏覽:672
php靜態變數銷毀 瀏覽:890
編程買蘋果電腦 瀏覽:764
flac演算法 瀏覽:501
reactnative與android 瀏覽:665