http://blog.csdn.net/morewindows/article/details/6709644 參考下
B. 寫一個簡單的JAVA排序程序
// 排序
public class Array
{
public static int[] random(int n) //產生n個隨機數,返回整型數組
{
if (n>0)
{
int table[] = new int[n];
for (int i=0; i<table.length; i++)
table[i] = (int)(Math.random()*100); //產生一個0~100之間的隨機數
return table; //返回一個數組
}
return null;
}
public static void print(int[] table) //輸出數組元素
{
if (table!=null)
for (int i=0; i<table.length; i++)
System.out.print(" "+table[i]);
System.out.println();
}
public static void insertSort(int[] table) //直接插入排序
{ //數組是引用類型,元素值將被改變
System.out.println("直接插入排序");
for (int i=1; i<table.length; i++) //n-1趟掃描
{
int temp=table[i], j; //每趟將table[i]插入到前面已排序的序列中
// System.out.print("移動");
for (j=i-1; j>-1 && temp<table[j]; j--) //將前面較大元素向後移動
{
// System.out.print(table[j]+", ");
table[j+1] = table[j];
}
table[j+1] = temp; //temp值到達插入位置
System.out.print("第"+i+"趟: ");
print(table);
}
}
public static void shellSort(int[] table) //希爾排序
{
System.out.println("希爾排序");
for (int delta=table.length/2; delta>0; delta/=2) //控制增量,增量減半,若干趟掃描
{
for (int i=delta; i<table.length; i++) //一趟中若干組,每個元素在自己所屬組內進行直接插入排序
{
int temp = table[i]; //當前待插入元素
int j=i-delta; //相距delta遠
while (j>=0 && temp<table[j]) //一組中前面較大的元素向後移動
{
table[j+delta] = table[j];
j-=delta; //繼續與前面的元素比較
}
table[j+delta] = temp; //插入元素位置
}
System.out.print("delta="+delta+" ");
print(table);
}
}
private static void swap(int[] table, int i, int j) //交換數組中下標為i、j的元素
{
if (i>=0 && i<table.length && j>=0 && j<table.length && i!=j) //判斷i、j是否越界
{
int temp = table[j];
table[j] = table[i];
table[i] = temp;
}
}
public static void bubbleSort(int[] table) //冒泡排序
{
System.out.println("冒泡排序");
boolean exchange=true; //是否交換的標記
for (int i=1; i<table.length && exchange; i++) //有交換時再進行下一趟,最多n-1趟
{
exchange=false; //假定元素未交換
for (int j=0; j<table.length-i; j++) //一次比較、交換
if (table[j]>table[j+1]) //反序時,交換
{
int temp = table[j];
table[j] = table[j+1];
table[j+1] = temp;
exchange=true; //有交換
}
System.out.print("第"+i+"趟: ");
print(table);
}
}
public static void quickSort(int[] table) //快速排序
{
quickSort(table, 0, table.length-1);
}
private static void quickSort(int[] table, int low, int high) //一趟快速排序,遞歸演算法
{ //low、high指定序列的下界和上界
if (low<high) //序列有效
{
int i=low, j=high;
int vot=table[i]; //第一個值作為基準值
while (i!=j) //一趟排序
{
while (i<j && vot<=table[j]) //從後向前尋找較小值
j--;
if (i<j)
{
table[i]=table[j]; //較小元素向前移動
i++;
}
while (i<j && table[i]<vot) //從前向後尋找較大值
i++;
if (i<j)
{
table[j]=table[i]; //較大元素向後移動
j--;
}
}
table[i]=vot; //基準值的最終位置
System.out.print(low+".."+high+", vot="+vot+" ");
print(table);
quickSort(table, low, j-1); //前端子序列再排序
quickSort(table, i+1, high); //後端子序列再排序
}
}
public static void selectSort(int[] table) //直接選擇排序
{
System.out.println("直接選擇排序");
for (int i=0; i<table.length-1; i++) //n-1趟排序
{ //每趟在從table[i]開始的子序列中尋找最小元素
int min=i; //設第i個數據元素最小
for (int j=i+1; j<table.length; j++) //在子序列中查找最小值
if (table[j]<table[min])
min = j; //記住最小元素下標
if (min!=i) //將本趟最小元素交換到前邊
{
int temp = table[i];
table[i] = table[min];
table[min] = temp;
}
System.out.print("第"+i+"趟: ");
print(table);
}
}
private static void sift(int[] table, int low, int high) //將以low為根的子樹調整成最小堆
{ //low、high是序列下界和上界
int i=low; //子樹的根
int j=2*i+1; //j為i結點的左孩子
int temp=table[i]; //獲得第i個元素的值
while (j<=high) //沿較小值孩子結點向下篩選
{
if (j<high && table[j]>table[j+1]) //數組元素比較(改成<為最大堆)
j++; //j為左右孩子的較小者
if (temp>table[j]) //若父母結點值較大(改成<為最大堆)
{
table[i]=table[j]; //孩子結點中的較小值上移
i=j; //i、j向下一層
j=2*i+1;
}
else
j=high+1; //退出循環
}
table[i]=temp; //當前子樹的原根值調整後的位置
System.out.print("sift "+low+".."+high+" ");
print(table);
}
public static void heapSort(int[] table)
{
System.out.println("堆排序");
int n=table.length;
for (int j=n/2-1; j>=0; j--) //創建最小堆
sift(table, j, n-1);
// System.out.println("最小堆? "+isMinHeap(table));
for (int j=n-1; j>0; j--) //每趟將最小值交換到後面,再調整成堆
{
int temp = table[0];
table[0] = table[j];
table[j] = temp;
sift(table, 0, j-1);
}
}
public static void mergeSort(int[] X) //歸並排序
{
System.out.println("歸並排序");
int n=1; //已排序的子序列長度,初值為1
int[] Y = new int[X.length]; //Y數組長度同X數組
do
{
mergepass(X, Y, n); //一趟歸並,將X數組中各子序列歸並到Y中
print(Y);
n*=2; //子序列長度加倍
if (n<X.length)
{
mergepass(Y, X, n); //將Y數組中各子序列再歸並到X中
print(X);
n*=2;
}
} while (n<X.length);
}
private static void mergepass(int[] X, int[] Y, int n) //一趟歸並
{
System.out.print("子序列長度n="+n+" ");
int i=0;
while (i<X.length-2*n+1)
{
merge(X,Y,i,i+n,n);
i += 2*n;
}
if (i+n<X.length)
merge(X,Y,i,i+n,n); //再一次歸並
else
for (int j=i; j<X.length; j++) //將X剩餘元素復制到Y中
Y[j]=X[j];
}
private static void merge(int[] X, int[] Y, int m, int r, int n) //一次歸並
{
int i=m, j=r, k=m;
while (i<r && j<r+n && j<X.length) //將X中兩個相鄰子序列歸並到Y中
if (X[i]<X[j]) //較小值復制到Y中
Y[k++]=X[i++];
else
Y[k++]=X[j++];
while (i<r) //將前一個子序列剩餘元素復制到Y中
Y[k++]=X[i++];
while (j<r+n && j<X.length) //將後一個子序列剩餘元素復制到Y中
Y[k++]=X[j++];
}
public static void main(String[] args)
{
// int[] table = {52,26,97,19,66,8,49};//Array.random(9);{49,65,13,81,76,97,38,49};////{85,12,36,24,47,30,53,91,76};//;//{4,5,8,1,2,7,3,6};// {32,26,87,72,26,17};//
int[] table = {13,27,38,49,97,76,49,81}; //最小堆
System.out.print("關鍵字序列: ");
Array.print(table);
// Array.insertSort(table);
// Array.shellSort(table);
// Array.bubbleSort(table);
// Array.quickSort(table);
// Array.selectSort(table);
// Array.heapSort(table);
// Array.mergeSort(table);
System.out.println("最小堆序列? "+Array.isMinHeap(table));
}
//第9章習題
public static boolean isMinHeap(int[] table) //判斷一個數據序列是否為最小堆
{
if (table==null)
return false;
int i = table.length/2 -1; //最深一棵子樹的根結點
while (i>=0)
{
int j=2*i+1; //左孩子
if (j<table.length)
if (table[i]>table[j])
return false;
else
if (j+1<table.length && table[i]>table[j+1]) //右孩子
return false;
i--;
}
return true;
}
}
/*
程序運行結果如下:
關鍵字序列: 32 26 87 72 26 17 8 40
直接插入排序
第1趟排序: 26 32 87 72 26 17 8 40
第2趟排序: 26 32 87 72 26 17 8 40
第3趟排序: 26 32 72 87 26 17 8 40
第4趟排序: 26 26 32 72 87 17 8 40 //排序演算法穩定
第5趟排序: 17 26 26 32 72 87 8 40
第6趟排序: 8 17 26 26 32 72 87 40
第7趟排序: 8 17 26 26 32 40 72 87
關鍵字序列: 42 1 74 25 45 29 87 53
直接插入排序
第1趟排序: 1 42 74 25 45 29 87 53
第2趟排序: 1 42 74 25 45 29 87 53
第3趟排序: 1 25 42 74 45 29 87 53
第4趟排序: 1 25 42 45 74 29 87 53
第5趟排序: 1 25 29 42 45 74 87 53
第6趟排序: 1 25 29 42 45 74 87 53
第7趟排序: 1 25 29 42 45 53 74 87
關鍵字序列: 21 12 2 40 99 97 68 57
直接插入排序
第1趟排序: 12 21 2 40 99 97 68 57
第2趟排序: 2 12 21 40 99 97 68 57
第3趟排序: 2 12 21 40 99 97 68 57
第4趟排序: 2 12 21 40 99 97 68 57
第5趟排序: 2 12 21 40 97 99 68 57
第6趟排序: 2 12 21 40 68 97 99 57
第7趟排序: 2 12 21 40 57 68 97 99
關鍵字序列: 27 38 65 97 76 13 27 49 55 4
希爾排序
delta=5 13 27 49 55 4 27 38 65 97 76
delta=2 4 27 13 27 38 55 49 65 97 76
delta=1 4 13 27 27 38 49 55 65 76 97
關鍵字序列: 49 38 65 97 76 13 27 49 55 4 //嚴書
希爾排序
delta=5 13 27 49 55 4 49 38 65 97 76
delta=2 4 27 13 49 38 55 49 65 97 76 //與嚴書不同
delta=1 4 13 27 38 49 49 55 65 76 97
關鍵字序列: 65 34 25 87 12 38 56 46 14 77 92 23
希爾排序
delta=6 56 34 14 77 12 23 65 46 25 87 92 38
delta=3 56 12 14 65 34 23 77 46 25 87 92 38
delta=1 12 14 23 25 34 38 46 56 65 77 87 92
關鍵字序列: 84 12 43 62 86 7 90 91
希爾排序
delta=4 84 7 43 62 86 12 90 91
delta=2 43 7 84 12 86 62 90 91
delta=1 7 12 43 62 84 86 90 91
關鍵字序列: 32 26 87 72 26 17
冒泡排序
第1趟排序: 26 32 72 26 17 87
第2趟排序: 26 32 26 17 72 87
第3趟排序: 26 26 17 32 72 87
第4趟排序: 26 17 26 32 72 87
第5趟排序: 17 26 26 32 72 87
關鍵字序列: 1 2 3 4 5 6 7 8
冒泡排序
第1趟排序: 1 2 3 4 5 6 7 8
關鍵字序列: 1 3 2 4 5 8 6 7
冒泡排序
第1趟排序: 1 2 3 4 5 6 7 8
第2趟排序: 1 2 3 4 5 6 7 8
關鍵字序列: 4 5 8 1 2 7 3 6
冒泡排序
第1趟排序: 4 5 1 2 7 3 6 8
第2趟排序: 4 1 2 5 3 6 7 8
第3趟排序: 1 2 4 3 5 6 7 8
第4趟排序: 1 2 3 4 5 6 7 8
第5趟排序: 1 2 3 4 5 6 7 8
關鍵字序列: 38 26 97 19 66 1 5 49
0..7, vot=38 5 26 1 19 38 66 97 49
0..3, vot=5 1 5 26 19 38 66 97 49
2..3, vot=26 1 5 19 26 38 66 97 49
5..7, vot=66 1 5 19 26 38 49 66 97
關鍵字序列: 38 5 49 26 19 97 1 66
0..7, vot=38 1 5 19 26 38 97 49 66
0..3, vot=1 1 5 19 26 38 97 49 66
1..3, vot=5 1 5 19 26 38 97 49 66
2..3, vot=19 1 5 19 26 38 97 49 66
5..7, vot=97 1 5 19 26 38 66 49 97
5..6, vot=66 1 5 19 26 38 49 66 97
關鍵字序列: 49 38 65 97 76 13 27 49
0..7, vot=49 49 38 27 13 49 76 97 65
0..3, vot=49 13 38 27 49 49 76 97 65
0..2, vot=13 13 38 27 49 49 76 97 65
1..2, vot=38 13 27 38 49 49 76 97 65
5..7, vot=76 13 27 38 49 49 65 76 97
關鍵字序列: 27 38 65 97 76 13 27 49 55 4
low=0 high=9 vot=27 4 27 13 27 76 97 65 49 55 38
low=0 high=2 vot=4 4 27 13 27 76 97 65 49 55 38
low=1 high=2 vot=27 4 13 27 27 76 97 65 49 55 38
low=4 high=9 vot=76 4 13 27 27 38 55 65 49 76 97
low=4 high=7 vot=38 4 13 27 27 38 55 65 49 76 97
low=5 high=7 vot=55 4 13 27 27 38 49 55 65 76 97
關鍵字序列: 38 26 97 19 66 1 5 49
直接選擇排序
第0趟排序: 1 26 97 19 66 38 5 49
第1趟排序: 1 5 97 19 66 38 26 49
第2趟排序: 1 5 19 97 66 38 26 49
第3趟排序: 1 5 19 26 66 38 97 49
第4趟排序: 1 5 19 26 38 66 97 49
第5趟排序: 1 5 19 26 38 49 97 66
第6趟排序: 1 5 19 26 38 49 66 97
最小堆
關鍵字序列: 81 49 76 27 97 38 49 13 65
sift 3..8 81 49 76 13 97 38 49 27 65
sift 2..8 81 49 38 13 97 76 49 27 65
sift 1..8 81 13 38 27 97 76 49 49 65
sift 0..8 13 27 38 49 97 76 49 81 65
13 27 38 49 97 76 49 81 65
sift 0..7 27 49 38 65 97 76 49 81 13
sift 0..6 38 49 49 65 97 76 81 27 13
sift 0..5 49 65 49 81 97 76 38 27 13
sift 0..4 49 65 76 81 97 49 38 27 13
sift 0..3 65 81 76 97 49 49 38 27 13
sift 0..2 76 81 97 65 49 49 38 27 13
sift 0..1 81 97 76 65 49 49 38 27 13
sift 0..0 97 81 76 65 49 49 38 27 13
最大堆
關鍵字序列: 49 65 13 81 76 27 97 38 49
sift 3..8 49 65 13 81 76 27 97 38 49
sift 2..8 49 65 97 81 76 27 13 38 49
sift 1..8 49 81 97 65 76 27 13 38 49
sift 0..8 97 81 49 65 76 27 13 38 49
97 81 49 65 76 27 13 38 49
sift 0..7 81 76 49 65 49 27 13 38 97
sift 0..6 76 65 49 38 49 27 13 81 97
sift 0..5 65 49 49 38 13 27 76 81 97
sift 0..4 49 38 49 27 13 65 76 81 97
sift 0..3 49 38 13 27 49 65 76 81 97
sift 0..2 38 27 13 49 49 65 76 81 97
sift 0..1 27 13 38 49 49 65 76 81 97
sift 0..0 13 27 38 49 49 65 76 81 97
關鍵字序列: 52 26 97 19 66 8 49
歸並排序
子序列長度n=1 26 52 19 97 8 66 49
子序列長度n=2 19 26 52 97 8 49 66
子序列長度n=4 8 19 26 49 52 66 97
關鍵字序列: 13 27 38 49 97 76 49 81 65
最小堆序列? true
*/
C. JAVA中有哪幾種常用的排序方法每個排序方法的實現思路是如何的每個方法的思想是什麼
一、冒泡排序
已知一組無序數據a[1]、a[2]、……a[n],需將其按升序排列。首先比較 a[1]與a[2]的值,若a[1]大於a[2]則交換兩者的值,否則不變。再比較a[2]與a[3]的值,若a[2]大於a[3]則交換兩者的值,否則不變。再比較a[3]與a[4],以此類推,最後比較a[n-1]與a[n]的值。這樣處理一輪後,a[n]的值一定是這組數據中最大的。再對 a[1]~a[n-1]以相同方法處理一輪,則a[n-1]的值一定是a[1]~a[n-1]中最大的。再對a[1]~a[n-2]以相同方法處理一輪,以此類推。共處理n-1輪後a[1]、a[2]、……a[n]就以升序排列了。
優點:穩定;
缺點:慢,每次只能移動相鄰兩個數據。
二、選擇排序
冒泡排序的改進版。
每一趟從待排序的數據元素中選出最小(或最大)的一個元素,順序放在已排好序的數列的最後,直到全部待排序的數據元素排完。
選擇排序是不穩定的排序方法。
n個記錄的文件的直接選擇排序可經過n-1趟直接選擇排序得到有序結果:
①初始狀態:無序區為R[1..n],有序區為空。
②第1趟排序
在無序區R[1..n]中選出關鍵字最小的記錄R[k],將它與無序區的第1個記錄R[1]交換,使R[1..1]和R[2..n]分別變為記錄個數增加1個的新有序區和記錄個數減少1個的新無序區。
……
③第i趟排序
第i趟排序開始時,當前有序區和無序區分別為R[1..i-1]和R(1≤i≤n- 1)。該趟排序從當前無序區中選出關鍵字最小的記錄 R[k],將它與無序區的第1個記錄R交換,使R[1..i]和R分別變為記錄個數增加1個的新有序區和記錄個數減少1個的新無序區。
這樣,n個記錄的文件的直接選擇排序可經過n-1趟直接選擇排序得到有序結果。
優點:移動數據的次數已知(n-1次);
缺點:比較次數多。
三、插入排序
已知一組升序排列數據a[1]、a[2]、……a[n],一組無序數據b[1]、 b[2]、……b[m],需將二者合並成一個升序數列。首先比較b[1]與a[1]的值,若b[1]大於a[1],則跳過,比較b[1]與a[2]的值,若b[1]仍然大於a[2],則繼續跳過,直到b[1]小於a數組中某一數據a[x],則將a[x]~a[n]分別向後移動一位,將b[1]插入到原來 a[x]的位置這就完成了b[1]的插入。b[2]~b[m]用相同方法插入。(若無數組a,可將b[1]當作n=1的數組a)
優點:穩定,快;
缺點:比較次數不一定,比較次數越少,插入點後的數據移動越多,特別是當數據總量龐大的時候,但用鏈表可以解決這個問題。
三、縮小增量排序
由希爾在1959年提出,又稱希爾排序(shell排序)。
已知一組無序數據a[1]、a[2]、……a[n],需將其按升序排列。發現當n不大時,插入排序的效果很好。首先取一增量d(d<n),將a[1]、a[1+d]、a[1+2d]……列為第一組,a[2]、a[2+d]、 a[2+2d]……列為第二組……,a[d]、a[2d]、a[3d]……列為最後一組以次類推,在各組內用插入排序,然後取d'<d,重復上述操作,直到d=1。
優點:快,數據移動少;
缺點:不穩定,d的取值是多少,應取多少個不同的值,都無法確切知道,只能憑經驗來取。
四、快速排序
快速排序是目前已知的最快的排序方法。
已知一組無序數據a[1]、a[2]、……a[n],需將其按升序排列。首先任取數據 a[x]作為基準。比較a[x]與其它數據並排序,使a[x]排在數據的第k位,並且使a[1]~a[k-1]中的每一個數據<a[x],a[k+1]~a[n]中的每一個數據>a[x],然後採用分治的策略分別對a[1]~a[k-1]和a[k+1]~a[n] 兩組數據進行快速排序。
優點:極快,數據移動少;
缺點:不穩定。
五、箱排序
已知一組無序正整數數據a[1]、a[2]、……a[n],需將其按升序排列。首先定義一個數組x[m],且m>=a[1]、a[2]、……a[n],接著循環n次,每次x[a]++.
優點:快,效率達到O(1)
缺點:數據范圍必須為正整數並且比較小
六、歸並排序
歸並排序是多次將兩個或兩個以上的有序表合並成一個新的有序表。最簡單的歸並是直接將兩個有序的子表合並成一個有序的表。
歸並排序是穩定的排序.即相等的元素的順序不會改變.如輸入記錄 1(1) 3(2) 2(3) 2(4) 5(5) (括弧中是記錄的關鍵字)時輸出的 1(1) 2(3) 2(4) 3(2) 5(5) 中的2 和 2 是按輸入的順序.這對要排序數據包含多個信息而要按其中的某一個信息排序,要求其它信息盡量按輸入的順序排列時很重要.這也是它比快速排序優勢的地方.
D. JAVA中堆和棧
堆棧是一種執行「後進先出」演算法的數據結構。
設想有一個直徑不大、一端開口一端封閉的竹筒。有若干個寫有編號的小球,小球的直徑比竹筒的直徑略小。現在把不同編號的小球放到竹筒裡面,可以發現一種規律:先放進去的小球只能後拿出來,反之,後放進去的小球能夠先拿出來。所以「先進後出」就是這種結構的特點。
堆棧就是這樣一種數據結構。它是在內存中開辟一個存儲區域,數據一個一個順序地存入(也就是「壓入——push」)這個區域之中。有一個地址指針總指向最後一個壓入堆棧的數據所在的數據單元,存放這個地址指針的寄存器就叫做堆棧指示器。開始放入數據的單元叫做「棧底」。數據一個一個地存入,這個過程叫做「壓棧」。在壓棧的過程中,每有一個數據壓入堆棧,就放在和前一個單元相連的後面一個單元中,堆棧指示器中的地址自動加1。讀取這些數據時,按照堆棧指示器中的地址讀取數據,堆棧指示器中的地址數自動減 1。這個過程叫做「彈出pop」。如此就實現了後進先出的原則。
堆棧是計算機中最常用的一種數據結構,比如函數的調用在計算機中是用堆棧實現的。
堆棧可以用數組存儲,也可以用以後會介紹的鏈表存儲。
下面是一個堆棧的結構體定義,包括一個棧頂指針,一個數據項數組。棧頂指針最開始指向-1,然後存入數據時,棧頂指針加1,取出數據後,棧頂指針減1。
#define MAX_SIZE 100
typedef int DATA_TYPE;
struct stack
{
DATA_TYPE data[MAX_SIZE];
int top;
};
在C++中,內存分成5個區,他們分別是堆、棧、自由存儲區、全局/靜態存儲區和常量存儲區。
棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的存儲區。裡面的變數通常是局部變數、函數參數等。
堆,就是那些由new分配的內存塊,他們的釋放編譯器不去管,由我們的應用程序去控制,一般一個new就要對應一個delete。如果程序員沒有釋放掉,那麼在程序結束後,操作系統會自動回收。
自由存儲區,就是那些由malloc等分配的內存塊,他和堆是十分相似的,不過它是用free來結束自己的生命的。
全局/靜態存儲區,全局變數和靜態變數被分配到同一塊內存中,在以前的C語言中,全局變數又分為初始化的和未初始化的,在C++裡面沒有這個區分了,他們共同佔用同一塊內存區。
常量存儲區,這是一塊比較特殊的存儲區,他們裡面存放的是常量,不允許修改(當然,你要通過非正當手段也可以修改,而且方法很多.
E. java堆排序代碼
//從a[index]到a[len]除了a[index]外其它元素滿足一個堆,把a[index]調整到合適位置
//這個堆滿足父節點>孩子結點,且要保證2*index能取到index的左孩子,
public static void adjustHeap(int[] a,int index,int len){
int scn=a[index];
for(int i=2*index;i<=m;i*=2){
if(i<m&&a[i]<a[i+1])i+=1;
if(!a[i]>scn)break;
a[index]=a[i];index=i;
}
a[index]=scn;
}
//數組a從a[1]開始存放元素,如果想從a[0]開始則要調整adjustHeap代碼,以便滿足完全二叉樹
//性質,代碼未經測試
public static void heapSort(int[] a){
for(int i=(a.length-1)/2;i>0;i--)
adjustHeap(a,i,a.length-1);
int tmp;
for(int i=a.length-1;i>1;i--){
tmp=a[i];
a[i]=a[1];
a[1]=tmp;
adjustHeap(a,1,i-1);
}
}
F. 以下代碼用java語句描述堆棧結構及演算法
摘要 1. Java中堆棧(stack)和堆(heap)
G. 數據結構 java開發中常用的排序演算法有哪些
排序演算法有很多,所以在特定情景中使用哪一種演算法很重要。為了選擇合適的演算法,可以按照建議的順序考慮以下標准:
(1)執行時間
(2)存儲空間
(3)編程工作
對於數據量較小的情形,(1)(2)差別不大,主要考慮(3);而對於數據量大的,(1)為首要。
主要排序法有:
一、冒泡(Bubble)排序——相鄰交換
二、選擇排序——每次最小/大排在相應的位置
三、插入排序——將下一個插入已排好的序列中
四、殼(Shell)排序——縮小增量
五、歸並排序
六、快速排序
七、堆排序
八、拓撲排序
一、冒泡(Bubble)排序
----------------------------------Code 從小到大排序n個數------------------------------------
void BubbleSortArray()
{
for(int i=1;i<n;i++)
{
for(int j=0;i<n-i;j++)
{
if(a[j]>a[j+1])//比較交換相鄰元素
{
int temp;
temp=a[j]; a[j]=a[j+1]; a[j+1]=temp;
}
}
}
}
-------------------------------------------------Code------------------------------------------------
效率 O(n²),適用於排序小列表。
二、選擇排序
----------------------------------Code 從小到大排序n個數--------------------------------
void SelectSortArray()
{
int min_index;
for(int i=0;i<n-1;i++)
{
min_index=i;
for(int j=i+1;j<n;j++)//每次掃描選擇最小項
if(arr[j]<arr[min_index]) min_index=j;
if(min_index!=i)//找到最小項交換,即將這一項移到列表中的正確位置
{
int temp;
temp=arr[i]; arr[i]=arr[min_index]; arr[min_index]=temp;
}
}
}
-------------------------------------------------Code-----------------------------------------
效率O(n²),適用於排序小的列表。
三、插入排序
--------------------------------------------Code 從小到大排序n個數-------------------------------------
void InsertSortArray()
{
for(int i=1;i<n;i++)//循環從第二個數組元素開始,因為arr[0]作為最初已排序部分
{
int temp=arr[i];//temp標記為未排序第一個元素
int j=i-1;
while (j>=0 && arr[j]>temp)/*將temp與已排序元素從小到大比較,尋找temp應插入的位置*/
{
arr[j+1]=arr[j];
j--;
}
arr[j+1]=temp;
}
}
------------------------------Code--------------------------------------------------------------
最佳效率O(n);最糟效率O(n²)與冒泡、選擇相同,適用於排序小列表
若列表基本有序,則插入排序比冒泡、選擇更有效率。
四、殼(Shell)排序——縮小增量排序
-------------------------------------Code 從小到大排序n個數-------------------------------------
void ShellSortArray()
{
for(int incr=3;incr<0;incr--)//增量遞減,以增量3,2,1為例
{
for(int L=0;L<(n-1)/incr;L++)//重復分成的每個子列表
{
for(int i=L+incr;i<n;i+=incr)//對每個子列表應用插入排序
{
int temp=arr[i];
int j=i-incr;
while(j>=0&&arr[j]>temp)
{
arr[j+incr]=arr[j];
j-=incr;
}
arr[j+incr]=temp;
}
}
}
}
--------------------------------------Code-------------------------------------------
適用於排序小列表。
效率估計O(nlog2^n)~O(n^1.5),取決於增量值的最初大小。建議使用質數作為增量值,因為如果增量值是2的冪,則在下一個通道中會再次比較相同的元素。
殼(Shell)排序改進了插入排序,減少了比較的次數。是不穩定的排序,因為排序過程中元素可能會前後跳躍。
五、歸並排序
----------------------------------------------Code 從小到大排序---------------------------------------
void MergeSort(int low,int high)
{
if(low>=high) return;//每個子列表中剩下一個元素時停止
else int mid=(low+high)/2;/*將列表劃分成相等的兩個子列表,若有奇數個元素,則在左邊子列表大於右側子列表*/
MergeSort(low,mid);//子列表進一步劃分
MergeSort(mid+1,high);
int [] B=new int [high-low+1];//新建一個數組,用於存放歸並的元素
for(int i=low,j=mid+1,k=low;i<=mid && j<=high;k++)/*兩個子列表進行排序歸並,直到兩個子列表中的一個結束*/
{
if (arr[i]<=arr[j];)
{
B[k]=arr[i];
I++;
}
else
{ B[k]=arr[j]; j++; }
}
for( ;j<=high;j++,k++)//如果第二個子列表中仍然有元素,則追加到新列表
B[k]=arr[j];
for( ;i<=mid;i++,k++)//如果在第一個子列表中仍然有元素,則追加到新列表中
B[k]=arr[i];
for(int z=0;z<high-low+1;z++)//將排序的數組B的 所有元素復制到原始數組arr中
arr[z]=B[z];
}
-----------------------------------------------------Code---------------------------------------------------
效率O(nlogn),歸並的最佳、平均和最糟用例效率之間沒有差異。
適用於排序大列表,基於分治法。
六、快速排序
------------------------------------Code--------------------------------------------
/*快速排序的演算法思想:選定一個樞紐元素,對待排序序列進行分割,分割之後的序列一個部分小於樞紐元素,一個部分大於樞紐元素,再對這兩個分割好的子序列進行上述的過程。*/ void swap(int a,int b){int t;t =a ;a =b ;b =t ;}
int Partition(int [] arr,int low,int high)
{
int pivot=arr[low];//採用子序列的第一個元素作為樞紐元素
while (low < high)
{
//從後往前栽後半部分中尋找第一個小於樞紐元素的元素
while (low < high && arr[high] >= pivot)
{
--high;
}
//將這個比樞紐元素小的元素交換到前半部分
swap(arr[low], arr[high]);
//從前往後在前半部分中尋找第一個大於樞紐元素的元素
while (low <high &&arr [low ]<=pivot )
{
++low ;
}
swap (arr [low ],arr [high ]);//將這個樞紐元素大的元素交換到後半部分
}
return low ;//返回樞紐元素所在的位置
}
void QuickSort(int [] a,int low,int high)
{
if (low <high )
{
int n=Partition (a ,low ,high );
QuickSort (a ,low ,n );
QuickSort (a ,n +1,high );
}
}
----------------------------------------Code-------------------------------------
平均效率O(nlogn),適用於排序大列表。
此演算法的總時間取決於樞紐值的位置;選擇第一個元素作為樞紐,可能導致O(n²)的最糟用例效率。若數基本有序,效率反而最差。選項中間值作為樞紐,效率是O(nlogn)。
基於分治法。
七、堆排序
最大堆:後者任一非終端節點的關鍵字均大於或等於它的左、右孩子的關鍵字,此時位於堆頂的節點的關鍵字是整個序列中最大的。
思想:
(1)令i=l,並令temp= kl ;
(2)計算i的左孩子j=2i+1;
(3)若j<=n-1,則轉(4),否則轉(6);
(4)比較kj和kj+1,若kj+1>kj,則令j=j+1,否則j不變;
(5)比較temp和kj,若kj>temp,則令ki等於kj,並令i=j,j=2i+1,並轉(3),否則轉(6)
(6)令ki等於temp,結束。
-----------------------------------------Code---------------------------
void HeapSort(SeqIAst R)
{ //對R[1..n]進行堆排序,不妨用R[0]做暫存單元 int I; BuildHeap(R); //將R[1-n]建成初始堆for(i=n;i>1;i--) //對當前無序區R[1..i]進行堆排序,共做n-1趟。{ R[0]=R[1]; R[1]=R[i]; R[i]=R[0]; //將堆頂和堆中最後一個記錄交換 Heapify(R,1,i-1); //將R[1..i-1]重新調整為堆,僅有R[1]可能違反堆性質 } } ---------------------------------------Code--------------------------------------
堆排序的時間,主要由建立初始堆和反復重建堆這兩部分的時間開銷構成,它們均是通過調用Heapify實現的。
堆排序的最壞時間復雜度為O(nlgn)。堆排序的平均性能較接近於最壞性能。 由於建初始堆所需的比較次數較多,所以堆排序不適宜於記錄數較少的文件。 堆排序是就地排序,輔助空間為O(1), 它是不穩定的排序方法。
堆排序與直接插入排序的區別:
直接選擇排序中,為了從R[1..n]中選出關鍵字最小的記錄,必須進行n-1次比較,然後在R[2..n]中選出關鍵字最小的記錄,又需要做n-2次比較。事實上,後面的n-2次比較中,有許多比較可能在前面的n-1次比較中已經做過,但由於前一趟排序時未保留這些比較結果,所以後一趟排序時又重復執行了這些比較操作。
堆排序可通過樹形結構保存部分比較結果,可減少比較次數。
八、拓撲排序
例 :學生選修課排課先後順序
拓撲排序:把有向圖中各頂點按照它們相互之間的優先關系排列成一個線性序列的過程。
方法:
在有向圖中選一個沒有前驅的頂點且輸出
從圖中刪除該頂點和所有以它為尾的弧
重復上述兩步,直至全部頂點均已輸出(拓撲排序成功),或者當圖中不存在無前驅的頂點(圖中有迴路)為止。
---------------------------------------Code--------------------------------------
void TopologicalSort()/*輸出拓撲排序函數。若G無迴路,則輸出G的頂點的一個拓撲序列並返回OK,否則返回ERROR*/
{
int indegree[M];
int i,k,j;
char n;
int count=0;
Stack thestack;
FindInDegree(G,indegree);//對各頂點求入度indegree[0....num]
InitStack(thestack);//初始化棧
for(i=0;i<G.num;i++)
Console.WriteLine("結點"+G.vertices[i].data+"的入度為"+indegree[i]);
for(i=0;i<G.num;i++)
{
if(indegree[i]==0)
Push(thestack.vertices[i]);
}
Console.Write("拓撲排序輸出順序為:");
while(thestack.Peek()!=null)
{
Pop(thestack.Peek());
j=locatevex(G,n);
if (j==-2)
{
Console.WriteLine("發生錯誤,程序結束。");
exit();
}
Console.Write(G.vertices[j].data);
count++;
for(p=G.vertices[j].firstarc;p!=NULL;p=p.nextarc)
{
k=p.adjvex;
if (!(--indegree[k]))
Push(G.vertices[k]);
}
}
if (count<G.num)
Cosole.WriteLine("該圖有環,出現錯誤,無法排序。");
else
Console.WriteLine("排序成功。");
}
----------------------------------------Code--------------------------------------
演算法的時間復雜度O(n+e)。
H. 排序都有哪幾種方法用JAVA實現一個快速排序。
排序的方法有:插入排序(直接插入排序、希爾排序),交換排序(冒泡排序、快速排序),選擇排序(直接選擇排序、堆排序),歸並排序,分配排序(箱排序、基數排序)
快速排序的偽代碼。
/ /使用快速排序方法對a[ 0 :n- 1 ]排序
從a[ 0 :n- 1 ]中選擇一個元素作為m i d d l e,該元素為支點
把餘下的元素分割為兩段left 和r i g h t,使得l e f t中的元素都小於等於支點,而right 中的元素都大於等於支點
遞歸地使用快速排序方法對left 進行排序
遞歸地使用快速排序方法對right 進行排序
所得結果為l e f t + m i d d l e + r i g h t
I. java中有堆排序演算法嗎
分為大根堆和小根堆,也就是畫成二叉樹的樣子,大根堆顧名思義就是大的在上面小的在下面,小根堆則相反,而且兩者都是從左子樹的葉子結點進行遍歷,找以葉子結點的那一分支進行比較