版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
排序是程序開發(fā)中一種非常常見的操作,對(duì)一組任意的數(shù)據(jù)元素(或記錄)經(jīng)過排序操作后,就可以把他們變成一組按關(guān)鍵字排序的有序隊(duì)列。對(duì)一個(gè)排序算法來說,一般從下面3個(gè)方面來衡量算法的優(yōu)劣:時(shí)間復(fù)雜度:它主要是分析關(guān)鍵字的比較次數(shù)和記錄的移動(dòng)次數(shù)??臻g復(fù)雜度:分析排序算法中需要多少輔助內(nèi)存。穩(wěn)定性:若兩個(gè)記錄A和B的關(guān)鍵字值相等,但是排序后A,B的先后次序保持不變,則稱這種排序算法是穩(wěn)定的;反之,就是不穩(wěn)定的。就現(xiàn)有的排序算法來看,排序大致可分為內(nèi)部排序和外部排序。如果整個(gè)排序過程不需要借助外部存儲(chǔ)器(如磁盤等),所有排序操作都是在內(nèi)存中完成,這種排序就被稱為內(nèi)部排序。如果參與排序的數(shù)據(jù)元素非常多,數(shù)據(jù)量非常大,計(jì)算無法把整個(gè)排序過程放在內(nèi)存中完成,必須借助于外部存儲(chǔ)器(如磁盤),這種排序就被稱為外部排序。外部排序最常用算噶是多路歸并排序,即將原文件分解稱多個(gè)能夠一次性裝入內(nèi)存的部分,分別把每一部分調(diào)入內(nèi)存完成排序,接下來再對(duì)多個(gè)有序的子文件進(jìn)行歸并排序。就常用的內(nèi)部排序算法來說,可以分為以下幾類:選擇排序(直接選擇排序,堆排序)交換排序(冒泡排序,快速排序)插入排序(直接插入排序,折半插入排序,Shell排序)歸并排序桶式排序基數(shù)排序Java排序算法(二):直接選擇排序直接選擇排序的基本操作就是每一趟從待排序的數(shù)據(jù)元素中選出最?。ɑ蜃畲螅┑囊粋€(gè)元素,順序放在已排好序的數(shù)列的最后,直到全部待排序的數(shù)據(jù)元素排完,它需要經(jīng)過n-1趟比較。算法不穩(wěn)定,O(1)的額外的空間,比較的時(shí)間復(fù)雜度為O(n^2),交換的時(shí)間復(fù)雜度為O(n),并不是自適應(yīng)的。在大多數(shù)情況下都不推薦使用。只有在希望減少交換次數(shù)的情況下可以用?;舅枷雗個(gè)記錄的文件的直接選擇排序可經(jīng)過n-1趟直接選擇排序得到有序結(jié)果:①初始狀態(tài):無序區(qū)為R[1..n],有序區(qū)為空。②第1趟排序在無序區(qū)R[1..n]中選出關(guān)鍵字最小的記錄R[k],將它與無序區(qū)的第1個(gè)記錄R[1]交換,使R[1..1]和R[2..n]分別變?yōu)橛涗泜€(gè)數(shù)增加1個(gè)的新有序區(qū)和記錄個(gè)數(shù)減少1個(gè)的新無序區(qū)?!鄣趇趟排序第i趟排序開始時(shí),當(dāng)前有序區(qū)和無序區(qū)分別為R[1..i-1]和R(1≤i≤n-1)。該趟排序從當(dāng)前無序區(qū)中選出關(guān)鍵字最小的記錄R[k],將它與無序區(qū)的第1個(gè)記錄R交換,使R[1..i]和R分別變?yōu)橛涗泜€(gè)數(shù)增加1個(gè)的新有序區(qū)和記錄個(gè)數(shù)減少1個(gè)的新無序區(qū)。這樣,n個(gè)記錄的文件的直接選擇排序可經(jīng)過n-1趟直接選擇排序得到有序結(jié)果。算法實(shí)現(xiàn)\o"viewplain"viewplainpublic
class
SelectSortTest{public
static
void
main(String[]args){int[]data=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7
};print(data);selectSort(data);print(data);}public
static
void
swap(int[]data,
int
i,
int
j){if
(i==j){return;}data[i]=data[i]+data[j];data[j]=data[i]-data[j];data[i]=data[i]-data[j];}public
static
void
selectSort(int[]data){for
(int
i=
0;i<data.length-
1;i++){int
minIndex=i;
//記錄最小值的索引for
(int
j=i+
1;j<data.length;j++){if
(data[j]<data[minIndex]){minIndex=j;
//若后面的元素值小于最小值,將j賦值給minIndex}}if
(minIndex!=i){swap(data,i,minIndex);print(data);}}}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}運(yùn)行結(jié)果:\o"viewplain"viewplain536219487136259487126359487123659487123459687123456987123456789123456789Java排序算法(三):堆排序堆積排序(Heapsort)是指利用堆積樹(堆)這種資料結(jié)構(gòu)所設(shè)計(jì)的一種排序算法,可以利用數(shù)組的特點(diǎn)快速定位指定索引的元素。堆排序是不穩(wěn)定的排序方法,輔助空間為O(1),最壞時(shí)間復(fù)雜度為O(nlog2n),堆排序的堆序的平均性能較接近于最壞性能。堆排序利用了大根堆(或小根堆)堆頂記錄的關(guān)鍵字最大(或最小)這一特征,使得在當(dāng)前無序區(qū)中選取最大(或最小)關(guān)鍵字的記錄變得簡(jiǎn)單。(1)用大根堆排序的基本思想①先將初始文件R[1..n]建成一個(gè)大根堆,此堆為初始的無序區(qū)②再將關(guān)鍵字最大的記錄R[1](即堆頂)和無序區(qū)的最后一個(gè)記錄R[n]交換,由此得到新的無序區(qū)R[1..n-1]和有序區(qū)R[n],且滿足R[1..n-1].keys≤R[n].key③由于交換后新的根R[1]可能違反堆性質(zhì),故應(yīng)將當(dāng)前無序區(qū)R[1..n-1]調(diào)整為堆。然后再次將R[1..n-1]中關(guān)鍵字最大的記錄R[1]和該區(qū)間的最后一個(gè)記錄R[n-1]交換,由此得到新的無序區(qū)R[1..n-2]和有序區(qū)R[n-1..n],且仍滿足關(guān)系R[1..n-2].keys≤R[n-1..n].keys,同樣要將R[1..n-2]調(diào)整為堆。……直到無序區(qū)只有一個(gè)元素為止。(2)大根堆排序算法的基本操作:①初始化操作:將R[1..n]構(gòu)造為初始堆;②每一趟排序的基本操作:將當(dāng)前無序區(qū)的堆頂記錄R[1]和該區(qū)間的最后一個(gè)記錄交換,然后將新的無序區(qū)調(diào)整為堆(亦稱重建堆)。注意:①只需做n-1趟排序,選出較大的n-1個(gè)關(guān)鍵字即可以使得文件遞增有序。②用小根堆排序與利用大根堆類似,只不過其排序結(jié)果是遞減有序的。堆排序和直接選擇排序相反:在任何時(shí)刻堆排序中無序區(qū)總是在有序區(qū)之前,且有序區(qū)是在原向量的尾部由后往前逐步擴(kuò)大至整個(gè)向量為止。代碼實(shí)現(xiàn):\o"viewplain"viewplain\o"copytoclipboard"copytoclipboardpublic
class
HeapSortTest{public
static
void
main(String[]args){int[]data5=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7
};print(data5);heapSort(data5);System.out.println("排序后的數(shù)組:");print(data5);}public
static
void
swap(int[]data,
int
i,
int
j){if
(i==j){return;}data[i]=data[i]+data[j];data[j]=data[i]-data[j];data[i]=data[i]-data[j];}public
static
void
heapSort(int[]data){for
(int
i=
0;i<data.length;i++){createMaxdHeap(data,data.length-
1
-i);swap(data,
0,data.length-
1
-i);print(data);}}public
static
void
createMaxdHeap(int[]data,
int
lastIndex){for
(int
i=(lastIndex-
1)/
2;i>=
0;i--){//保存當(dāng)前正在判斷的節(jié)點(diǎn)int
k=i;//若當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)存在while
(2
*k+
1
<=lastIndex){//biggerIndex總是記錄較大節(jié)點(diǎn)的值,先賦值為當(dāng)前判斷節(jié)點(diǎn)的左子節(jié)點(diǎn)int
biggerIndex=
2
*k+
1;if
(biggerIndex<lastIndex){//若右子節(jié)點(diǎn)存在,否則此時(shí)biggerIndex應(yīng)該等于lastIndexif
(data[biggerIndex]<data[biggerIndex+
1]){//若右子節(jié)點(diǎn)值比左子節(jié)點(diǎn)值大,則biggerIndex記錄的是右子節(jié)點(diǎn)的值biggerIndex++;}}if
(data[k]<data[biggerIndex]){//若當(dāng)前節(jié)點(diǎn)值比子節(jié)點(diǎn)最大值小,則交換2者得值,交換后將biggerIndex值賦值給kswap(data,k,biggerIndex);k=biggerIndex;}
else
{break;}}}}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}
運(yùn)行結(jié)果:\o"viewplain"viewplain\o"copytoclipboard"copytoclipboard5
3
6
2
1
9
4
8
73
8
6
7
1
5
4
2
92
7
6
3
1
5
4
8
94
3
6
2
1
5
7
8
94
3
5
2
1
6
7
8
91
3
4
2
5
6
7
8
92
3
1
4
5
6
7
8
91
2
3
4
5
6
7
8
91
2
3
4
5
6
7
8
91
2
3
4
5
6
7
8
9排序后的數(shù)組:1
2
3
4
5
6
7
8
9
整個(gè)排序過程圖解:(待有時(shí)間再補(bǔ)充...)Java排序算法(四):冒泡排序冒泡排序是計(jì)算機(jī)的一種排序方法,它的時(shí)間復(fù)雜度為O(n^2),雖然不及堆排序、快速排序的O(nlogn,底數(shù)為2),但是有兩個(gè)優(yōu)點(diǎn):1.“編程復(fù)雜度”很低,很容易寫出代碼;2.具有穩(wěn)定性,這里的穩(wěn)定性是指原序列中相同元素的相對(duì)順序仍然保持到排序后的序列,而堆排序、快速排序均不具有穩(wěn)定性。不過,一路、二路歸并排序、不平衡二叉樹排序的速度均比冒泡排序快,且具有穩(wěn)定性,但速度不及堆排序、快速排序。冒泡排序是經(jīng)過n-1趟子排序完成的,第i趟子排序從第1個(gè)數(shù)至第n-i個(gè)數(shù),若第i個(gè)數(shù)比后一個(gè)數(shù)大(則升序,小則降序)則交換兩數(shù)。冒泡排序算法穩(wěn)定,O(1)的額外的空間,比較和交換的時(shí)間復(fù)雜度都是O(n^2),自適應(yīng),對(duì)于已基本排序的算法,時(shí)間復(fù)雜度為O(n)。冒泡算法的許多性質(zhì)和插入算法相似,但對(duì)于系統(tǒng)開銷高一點(diǎn)點(diǎn)。排序過程設(shè)想被排序的數(shù)組R[1..N]垂直豎立,將每個(gè)數(shù)據(jù)元素看作有重量的氣泡,根據(jù)輕氣泡不能在重氣泡之下的原則,從下往上掃描數(shù)組R,凡掃描到違反本原則的輕氣泡,就使其向上"漂浮",如此反復(fù)進(jìn)行,直至最后任何兩個(gè)氣泡都是輕者在上,重者在下為止。代碼實(shí)現(xiàn)\o"viewplain"viewplainpublic
class
BubbleSortTest{public
static
void
main(String[]args){int[]data5=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7};print(data5);bubbleSort(data5);System.out.println("排序后的數(shù)組:");print(data5);}public
static
void
swap(int[]data,
int
i,
int
j){if
(i==j){return;}data[i]=data[i]+data[j];data[j]=data[i]-data[j];data[i]=data[i]-data[j];}public
static
void
bubbleSort(int[]data){for
(int
i=
0;i<data.length-
1;i++){//記錄某趟是否發(fā)生交換,若為false表示數(shù)組已處于有序狀態(tài)boolean
isSorted=
false;for
(int
j=
0;j<data.length-i-
1;j++){if
(data[j]>data[j+
1]){swap(data,j,j+
1);isSorted=
true;print(data);}}if
(!isSorted){//若數(shù)組已處于有序狀態(tài),結(jié)束循環(huán)break;}}}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}
運(yùn)行結(jié)果\o"viewplain"viewplain5
3
6
2
1
9
4
8
73
5
6
2
1
9
4
8
73
5
2
6
1
9
4
8
73
5
2
1
6
9
4
8
73
5
2
1
6
4
9
8
73
5
2
1
6
4
8
9
73
5
2
1
6
4
8
7
93
2
5
1
6
4
8
7
93
2
1
5
6
4
8
7
93
2
1
5
4
6
8
7
93
2
1
5
4
6
7
8
92
3
1
5
4
6
7
8
92
1
3
5
4
6
7
8
92
1
3
4
5
6
7
8
91
2
3
4
5
6
7
8
9排序后的數(shù)組:1
2
3
4
5
6
7
8
9Java排序算法(五):快速排序快速排序是一個(gè)速度非??斓慕粨Q排序算法,它的基本思路很簡(jiǎn)單,從待排的數(shù)據(jù)序列中任取一個(gè)數(shù)據(jù)(如第一個(gè)數(shù)據(jù))作為分界值,所有比它小的數(shù)據(jù)元素放到左邊,所有比它大的數(shù)據(jù)元素放到它的右邊。經(jīng)過這樣一趟下來,該序列形成左右兩個(gè)子序列,左邊序列中的數(shù)據(jù)元素的值都比分界值小,右邊序列中數(shù)據(jù)元素的值都比分界值大。
接下來對(duì)左右兩個(gè)子序列進(jìn)行遞歸排序,對(duì)兩個(gè)子序列重新選擇中心元素并依此規(guī)則調(diào)整,直到每個(gè)元素子表的元素只剩下一個(gè)元素,排序完成。思路:
1.定義一個(gè)i變量,i變量從左邊第一個(gè)索引開始,找大于分界值的元素的索引,并用i來記錄它。
2.定義一個(gè)j變量,j變量從右邊第一個(gè)索引開始,找小于分界值的元素的索引,并用j來記錄它。
3.如果i<j,交換i,j兩個(gè)索引處的元素。
重復(fù)執(zhí)行以上1,2,3步,直到i>=j,可以判斷j左邊的數(shù)據(jù)元素都小于分界值,j右邊的數(shù)據(jù)元素都大于分界值,最后將分界值和j索引處的元素交換即可。時(shí)間復(fù)雜度
最好情況(每次總是選到中間值作樞軸)T(n)=O(nlogn)
最壞情況(每次總是選到最小或最大元素作樞軸)
做n-1趟,每趟比較n-i次,總的比較次數(shù)最大:[O(n2)]
平均時(shí)間復(fù)雜度為::T(n)=O(nlogn)代碼實(shí)現(xiàn):\o"viewplain"viewplainpackage
sort;public
class
QuickSortTest{public
static
void
main(String[]args){int[]data=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7
};print(data);quickSort(data,
0,data.length-
1);System.out.println("排序后的數(shù)組:");print(data);}public
static
void
swap(int[]data,
int
i,
int
j){if
(i==j){return;}data[i]=data[i]+data[j];data[j]=data[i]-data[j];data[i]=data[i]-data[j];}public
static
void
quickSort(int[]data,
int
start,
int
end){if
(start>=end)return;//以起始索引為分界點(diǎn)int
pivot=data[start];int
i=start+
1;int
j=end;while
(true){while
(i<=end&&data[i]<pivot){i++;}while
(j>start&&data[j]>pivot){j--;}if
(i<j){swap(data,i,j);}
else
{break;}}//交換j和分界點(diǎn)的值swap(data,start,j);print(data);//遞歸左子序列quickSort(data,start,j-
1);//遞歸右子序列quickSort(data,j+
1,end);}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}
運(yùn)行結(jié)果:\o"viewplain"viewplain5
3
6
2
1
9
4
8
71
3
4
2
5
9
6
8
71
3
4
2
5
9
6
8
71
2
3
4
5
9
6
8
71
2
3
4
5
7
6
8
91
2
3
4
5
6
7
8
9排序后的數(shù)組:1
2
3
4
5
6
7
8
9Java排序算法(六):直接插入排序直接插入排序的基本操作就是將待排序的數(shù)據(jù)元素按其關(guān)鍵字值的大小插入到前面的有序序列中。直接插入的時(shí)間效率并不高,如果在最壞的情況下,所有元素的比較次數(shù)總和為(0+1+...+n-1)=O(n^2)。其他情況下也要考慮移動(dòng)元素的次數(shù),故時(shí)間復(fù)雜度為O(n^2)直接插入空間效率很好,只需要1個(gè)緩存數(shù)據(jù)單元,也就是說空間復(fù)雜度為O(1).直接插入排序是穩(wěn)定的。直接插入排序在數(shù)據(jù)已有一定順序的情況下,效率較好。但如果數(shù)據(jù)無規(guī)則,則需要移動(dòng)大量的數(shù)據(jù),其效率就與冒泡排序法和選擇排序法一樣差了。算法描述對(duì)一個(gè)有n個(gè)元素的數(shù)據(jù)序列,排序需要進(jìn)行n-1趟插入操作:第1趟插入,將第2個(gè)元素插入前面的有序子序列--此時(shí)前面只有一個(gè)元素,當(dāng)然是有序的。第2趟插入,將第3個(gè)元素插入前面的有序子序列,前面2個(gè)元素是有序的。第n-1趟插入,將第n個(gè)元素插入前面的有序子序列,前面n-1個(gè)元素是有序的。代碼實(shí)現(xiàn)\o"viewplain"viewplainpackage
sort;public
class
InsertSortTest{public
static
int
count=
0;public
static
void
main(String[]args){int[]data=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7
};print(data);insertSort(data);print(data);}public
static
void
insertSort(int[]data){for
(int
i=
1;i<data.length;i++){//緩存i處的元素值int
tmp=data[i];if
(data[i]<data[i-
1]){int
j=i-
1;//整體后移一格while
(j>=
0
&&data[j]>tmp){data[j+
1]=data[j];j--;}//最后將tmp插入合適的位置data[j+
1]=tmp;print(data);}}}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}
運(yùn)行結(jié)果:\o"viewplain"viewplain5
3
6
2
1
9
4
8
73
5
6
2
1
9
4
8
72
3
5
6
1
9
4
8
71
2
3
5
6
9
4
8
71
2
3
4
5
6
9
8
71
2
3
4
5
6
8
9
71
2
3
4
5
6
7
8
91
2
3
4
5
6
7
8
9\o"Java排序算法(七):折半插入排序"Java排序算法(七):折半插入排序分類:
JavaSE
Java排序2011-07-0621:10
81人閱讀
評(píng)論(2)
\o"收藏"收藏
\o"舉報(bào)"舉報(bào)Java排序算法(七):折半插入排序折半插入排序法,又稱二分插入排序法,是直接插入排序法的改良版,也需要執(zhí)行i-1趟插入,不同之處在于,第i趟插入,先找出第i+1個(gè)元素應(yīng)該插入的的位置,假定前i個(gè)數(shù)據(jù)是已經(jīng)處于有序狀態(tài)。代碼實(shí)現(xiàn):\o"viewplain"viewplainpackage
sort;public
class
BinaryInsertSortTest{public
static
int
count=
0;public
static
void
main(String[]args){int[]data=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7
};print(data);binaryInsertSort(data);print(data);}public
static
void
binaryInsertSort(int[]data){for
(int
i=
1;i<data.length;i++){if
(data[i]<data[i-
1]){//緩存i處的元素值int
tmp=data[i];//記錄搜索范圍的左邊界int
low=
0;//記錄搜索范圍的右邊界int
high=i-
1;while
(low<=high){//記錄中間位置int
mid=(low+high)/
2;//比較中間位置數(shù)據(jù)和i處數(shù)據(jù)大小,以縮小搜索范圍if
(data[mid]<tmp){low=mid+
1;}
else
{high=mid-
1;}}//將low~i處數(shù)據(jù)整體向后移動(dòng)1位for
(int
j=i;j>low;j--){data[j]=data[j-
1];}data[low]=tmp;print(data);}}}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}運(yùn)行結(jié)果:\o"viewplain"viewplain5
3
6
2
1
9
4
8
73
5
6
2
1
9
4
8
72
3
5
6
1
9
4
8
71
2
3
5
6
9
4
8
71
2
3
4
5
6
9
8
71
2
3
4
5
6
8
9
71
2
3
4
5
6
7
8
91
2
3
4
5
6
7
8
9Java排序算法(八):希爾排序(Shell排序)希爾排序(縮小增量法)屬于插入類排序,由Shell提出,希爾排序?qū)χ苯硬迦肱判蜻M(jìn)行了簡(jiǎn)單的改進(jìn):它通過加大插入排序中元素之間的間隔,并在這些有間隔的元素中進(jìn)行插入排序,從而使數(shù)據(jù)項(xiàng)大跨度地移動(dòng),當(dāng)這些數(shù)據(jù)項(xiàng)排過一趟序之后,希爾排序算法減小數(shù)據(jù)項(xiàng)的間隔再進(jìn)行排序,依次進(jìn)行下去,進(jìn)行這些排序時(shí)的數(shù)據(jù)項(xiàng)之間的間隔被稱為增量,習(xí)慣上用字母h來表示這個(gè)增量。常用的h序列由Knuth提出,該序列從1開始,通過如下公式產(chǎn)生:h=3*h+1反過來程序需要反向計(jì)算h序列,應(yīng)該使用h=(h-1)/3代碼實(shí)現(xiàn):\o"viewplain"viewplainpackage
sort;public
class
ShellSortTest{public
static
int
count=
0;public
static
void
main(String[]args){int[]data=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7
};print(data);shellSort(data);print(data);}public
static
void
shellSort(int[]data){//計(jì)算出最大的h值int
h=
1;while
(h<=data.length/
3){h=h*
3
+
1;}while
(h>
0){for
(int
i=h;i<data.length;i+=h){if
(data[i]<data[i-h]){int
tmp=data[i];int
j=i-h;while
(j>=
0
&&data[j]>tmp){data[j+h]=data[j];j-=h;}data[j+h]=tmp;print(data);}}//計(jì)算出下一個(gè)h值h=(h-
1)/
3;}}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}
運(yùn)行結(jié)果:\o"viewplain"viewplain5
3
6
2
1
9
4
8
71
3
6
2
5
9
4
8
71
2
3
6
5
9
4
8
71
2
3
5
6
9
4
8
71
2
3
4
5
6
9
8
71
2
3
4
5
6
8
9
71
2
3
4
5
6
7
8
91
2
3
4
5
6
7
8
9
上面程序在和直接插入法比較,會(huì)發(fā)現(xiàn)其與直接插入排序的差別在于:直接插入排序中的h會(huì)以1代替Shell排序是不穩(wěn)定的,它的空間開銷也是O(1),時(shí)間開銷估計(jì)在O(N3/2)~O(N7/6)之間Java排序算法(九):歸并排序歸并排序(Merge)是將兩個(gè)(或兩個(gè)以上)有序表合并成一個(gè)新的有序表,即把待排序序列分為若干個(gè)子序列,每個(gè)子序列是有序的。然后再把有序子序列合并為整體有序序列。歸并排序是建立在歸并操作上的一種有效的排序算法。該算法是采用分治法(DivideandConquer)的一個(gè)非常典型的應(yīng)用。將已有序的子序列合并,得到完全有序的序列;即先使每個(gè)子序列有序,再使子序列段間有序。若將兩個(gè)有序表合并成一個(gè)有序表,稱為2-路歸并。歸并排序算法穩(wěn)定,數(shù)組需要O(n)的額外空間,鏈表需要O(log(n))的額外空間,時(shí)間復(fù)雜度為O(nlog(n)),算法不是自適應(yīng)的,不需要對(duì)數(shù)據(jù)的隨機(jī)讀取。工作原理:1、申請(qǐng)空間,使其大小為兩個(gè)已經(jīng)排序序列之和,該空間用來存放合并后的序列2、設(shè)定兩個(gè)指針,最初位置分別為兩個(gè)已經(jīng)排序序列的起始位置3、比較兩個(gè)指針?biāo)赶虻脑兀x擇相對(duì)小的元素放入到合并空間,并移動(dòng)指針到下一位置4、重復(fù)步驟3直到某一指針達(dá)到序列尾5、將另一序列剩下的所有元素直接復(fù)制到合并序列尾代碼實(shí)現(xiàn):\o"viewplain"viewplainpublic
class
MergeSortTest{public
static
void
main(String[]args){int[]data=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7
};print(data);mergeSort(data);System.out.println("排序后的數(shù)組:");print(data);}public
static
void
mergeSort(int[]data){sort(data,
0,data.length-
1);}public
static
void
sort(int[]data,
int
left,
int
right){if
(left>=right)return;//找出中間索引int
center=(left+right)/
2;//對(duì)左邊數(shù)組進(jìn)行遞歸sort(data,left,center);//對(duì)右邊數(shù)組進(jìn)行遞歸sort(data,center+
1,right);//合并merge(data,left,center,right);print(data);}/***將兩個(gè)數(shù)組進(jìn)行歸并,歸并前面2個(gè)數(shù)組已有序,歸并后依然有序**@paramdata*數(shù)組對(duì)象*@paramleft*左數(shù)組的第一個(gè)元素的索引*@paramcenter*左數(shù)組的最后一個(gè)元素的索引,center+1是右數(shù)組第一個(gè)元素的索引*@paramright*右數(shù)組最后一個(gè)元素的索引*/public
static
void
merge(int[]data,
int
left,
int
center,
int
right){//臨時(shí)數(shù)組int[]tmpArr=
new
int[data.length];//右數(shù)組第一個(gè)元素索引int
mid=center+
1;//third記錄臨時(shí)數(shù)組的索引int
third=left;//緩存左數(shù)組第一個(gè)元素的索引int
tmp=left;while
(left<=center&&mid<=right){//從兩個(gè)數(shù)組中取出最小的放入臨時(shí)數(shù)組if
(data[left]<=data[mid]){tmpArr[third++]=data[left++];}
else
{tmpArr[third++]=data[mid++];}}//剩余部分依次放入臨時(shí)數(shù)組(實(shí)際上兩個(gè)while只會(huì)執(zhí)行其中一個(gè))while
(mid<=right){tmpArr[third++]=data[mid++];}while
(left<=center){tmpArr[third++]=data[left++];}//將臨時(shí)數(shù)組中的內(nèi)容拷貝回原數(shù)組中//(原left-right范圍的內(nèi)容被復(fù)制回原數(shù)組)while
(tmp<=right){data[tmp]=tmpArr[tmp++];}}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}運(yùn)行結(jié)果:\o"viewplain"viewplain5
3
6
2
1
9
4
8
73
5
6
2
1
9
4
8
73
5
6
2
1
9
4
8
73
5
6
1
2
9
4
8
71
2
3
5
6
9
4
8
71
2
3
5
6
4
9
8
71
2
3
5
6
4
9
7
81
2
3
5
6
4
7
8
91
2
3
4
5
6
7
8
9排序后的數(shù)組:1
2
3
4
5
6
7
8
9Java排序算法(十):桶式排序桶式排序不再是一種基于比較的排序方法,它是一種比較巧妙的排序方式,但這種排序方式需要待排序的序列滿足以下兩個(gè)特征:待排序列所有的值處于一個(gè)可枚舉的范圍之類;待排序列所在的這個(gè)可枚舉的范圍不應(yīng)該太大,否則排序開銷太大。排序的具體步驟如下:(1)對(duì)于這個(gè)可枚舉范圍構(gòu)建一個(gè)buckets數(shù)組,用于記錄“落入”每個(gè)桶中元素的個(gè)數(shù);(2)將(1)中得到的buckets數(shù)組重新進(jìn)行計(jì)算,按如下公式重新計(jì)算:buckets[i]=buckets[i]+buckets[i-1](其中1<=i<buckets.length);桶式排序是一種非常優(yōu)秀的排序算法,時(shí)間效率極高,它只要通過2輪遍歷:第1輪遍歷待排數(shù)據(jù),統(tǒng)計(jì)每個(gè)待排數(shù)據(jù)“落入”各桶中的個(gè)數(shù),第2輪遍歷buckets用于重新計(jì)算buckets中元素的值,2輪遍歷后就可以得到每個(gè)待排數(shù)據(jù)在有序序列中的位置,然后將各個(gè)數(shù)據(jù)項(xiàng)依次放入指定位置即可。桶式排序的空間開銷較大,它需要兩個(gè)數(shù)組,第1個(gè)buckets數(shù)組用于記錄“落入”各桶中元素的個(gè)數(shù),進(jìn)而保存各元素在有序序列中的位置,第2個(gè)數(shù)組用于緩存待排數(shù)據(jù)。桶式排序是穩(wěn)定的。如果待排序數(shù)據(jù)的范圍在0~k之間,那么它的時(shí)間復(fù)雜度是O(k+n)的桶式排序算法速度很快,因?yàn)樗臅r(shí)間復(fù)雜度是O(k+n),而基于交換的排序時(shí)間上限是nlg
n。但是它的限制多,比如它只能排整形數(shù)組。而且當(dāng)k較大,而數(shù)組長(zhǎng)度n較小,即k>>n時(shí),輔助數(shù)組C[k+1]的空間消耗較大。當(dāng)數(shù)組為整形,且k和n接近時(shí),可以用此方法排序。(有的文章也稱這種排序算法為“計(jì)數(shù)排序”)代碼實(shí)現(xiàn):\o"viewplain"viewplainpublic
class
BucketSortTest{public
static
int
count=
0;public
static
void
main(String[]args){int[]data=
new
int[]{
5,
3,
6,
2,
1,
9,
4,
8,
7
};print(data);bucketSort(data,
0,
10);print(data);}public
static
void
bucketSort(int[]data,
int
min,
int
max){//緩存數(shù)組int[]tmp=
new
int[data.length];//buckets用于記錄待排序元素的信息//buckets數(shù)組定義了max-min個(gè)桶int[]buckets=
new
int[max-min];//計(jì)算每個(gè)元素在序列出現(xiàn)的次數(shù)for
(int
i=
0;i<data.length;i++){buckets[data[i]-min]++;}//計(jì)算“落入”各桶內(nèi)的元素在有序序列中的位置for
(int
i=
1;i<max-min;i++){buckets[i]=buckets[i]+buckets[i-
1];}//將data中的元素完全復(fù)制到tmp數(shù)組中System.arraycopy(data,
0,tmp,
0,data.length);//根據(jù)buckets數(shù)組中的信息將待排序列的各元素放入相應(yīng)位置for
(int
k=data.length-
1;k>=
0;k--){data[--buckets[tmp[k]-min]]=tmp[k];}}public
static
void
print(int[]data){for
(int
i=
0;i<data.length;i++){System.out.print(data[i]+
"\t");}System.out.println();}}
運(yùn)行結(jié)果:\o"viewplain"viewplain5
3
6
2
1
9
4
8
71
2
3
4
5
6
7
8
9Java排序算法(十一):基數(shù)排序基數(shù)排序已經(jīng)不再是一種常規(guī)的排序方式,它更多地像一種排序方法的應(yīng)用,基數(shù)排序必須依賴于另外的排序方法。基數(shù)排序的總體思路就是將待排序數(shù)據(jù)拆分成多個(gè)關(guān)鍵字進(jìn)行排序,也就是說,基數(shù)排序的實(shí)質(zhì)是多關(guān)鍵字排序。多關(guān)鍵字排序的思路是將待排數(shù)據(jù)里德排序關(guān)鍵字拆分成多個(gè)排序關(guān)鍵字;第1個(gè)排序關(guān)鍵字,第2個(gè)排序關(guān)鍵字,第3個(gè)排序關(guān)鍵字......然后,根據(jù)子關(guān)鍵字對(duì)待排序數(shù)據(jù)進(jìn)行排序。多關(guān)鍵字排序時(shí)有兩種解決方案:最高位優(yōu)先法(MSD)(MostSignificantDigitfirst)最低位優(yōu)先法(LSD)(LeastSignificantDigitfirst)例如,對(duì)如下數(shù)據(jù)序列進(jìn)行排序。192,221,12,23可以觀察到它的每個(gè)數(shù)據(jù)至多只有3位,因此可以將每個(gè)數(shù)據(jù)拆分成3個(gè)關(guān)鍵字:百位(高位)、十位、個(gè)位(低位)。如果按照習(xí)慣思維,會(huì)先比較百位,百位大的數(shù)據(jù)大,百位相同的再比較十位,十位大的數(shù)據(jù)大;最后再比較個(gè)位。人得習(xí)慣思維是最高位優(yōu)先方式。如果按照人得思維方式,計(jì)算機(jī)實(shí)現(xiàn)起來有一定的困難,當(dāng)開始比較十位時(shí),程序還需要判斷它們的百位是否相同--這就認(rèn)為地增加了難度,計(jì)算機(jī)通常會(huì)選擇最低位優(yōu)先法。基數(shù)排序方法對(duì)任一子關(guān)鍵字排序時(shí)必須借助于另一種排序方法,而且這種排序方法必
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度生態(tài)旅游開發(fā)與環(huán)境保護(hù)合同
- 2025年度個(gè)人額度借款合同范本風(fēng)險(xiǎn)防控策略
- 2025年度化妝品行業(yè)培訓(xùn)與專業(yè)人才培養(yǎng)合同
- 二零二五年度二手房出售過戶手續(xù)代理服務(wù)合同4篇
- 2025年度國(guó)際物流運(yùn)輸與海關(guān)申報(bào)服務(wù)合同
- 2025年度體育用品采購(gòu)合同協(xié)議
- 2025年度電子信息產(chǎn)品購(gòu)銷合同樣本
- 2025年度航空航天設(shè)備采購(gòu)合同協(xié)議細(xì)則
- 2025年創(chuàng)業(yè)投資股權(quán)轉(zhuǎn)讓與投資管理合同
- 2025年度新能源發(fā)電設(shè)備采購(gòu)合同協(xié)議范本模板
- 新疆烏魯木齊地區(qū)2025年高三年級(jí)第一次質(zhì)量監(jiān)測(cè)生物學(xué)試卷(含答案)
- 衛(wèi)生服務(wù)個(gè)人基本信息表
- 高中英語北師大版必修第一冊(cè)全冊(cè)單詞表(按單元編排)
- 苗圃建設(shè)項(xiàng)目施工組織設(shè)計(jì)范本
- 廣東省湛江市廉江市2023-2024學(xué)年八年級(jí)上學(xué)期期末考試數(shù)學(xué)試卷(含答案)
- 學(xué)校食品安全舉報(bào)投訴處理制度
- 安徽省蕪湖市2023-2024學(xué)年高一上學(xué)期期末考試 生物 含解析
- 交叉口同向可變車道動(dòng)態(tài)控制與信號(hào)配時(shí)優(yōu)化研究
- 安華農(nóng)業(yè)保險(xiǎn)股份有限公司北京市地方財(cái)政生豬價(jià)格指數(shù)保險(xiǎn)條款(風(fēng)險(xiǎn)敏感型)
- 技術(shù)交易系統(tǒng)的新概念
- 通用電子嘉賓禮薄
評(píng)論
0/150
提交評(píng)論