Java演算法——————七大排序
排序演算法的分類:
排序:基本排序:{交換排序:氣泡排序,快速排序。
{選擇排序:選擇排序,堆排序
{插入排序:直接插入排序,Shell排序
{歸併排序
多路歸併排序:
一:交換排序
1:交換排序的主體操作是對陣列中的資料不斷進行交換操作。
2:交換排序種類:交換排序主要有氣泡排序和快速排序。
1:氣泡排序
(1)氣泡排序流程
——(1)對陣列中的各元素,一次比較相鄰的兩個元素的大小
——(2)如果前面的資料大於後面的資料,就交換著兩個資料。經過第一輪的多次比較排序之後,便可將最小的資料排好
——(3)在用同樣的方法把剩下的資料逐個進行比較,最後便可按照從小到大的順序排好陣列個數據的順序。
(2)冒泡程式碼分析
優點:思路簡單直觀。
缺點:執行的步驟有點長,效率不是很高。
時間效率:時間複雜度為O(n^2),平均O(n^2) ,最壞O(n^2),空間O(1),穩定
空間效率:僅使用了一個輔存單元。
(3)氣泡排序程式碼
public void bubblesort(){ int[] data={10,9,8,7,6,5,4}; System.out.println("排序之前"); System.out.println(java.util.Arrays.toString(data)); int n=data.length; for(int i=0;i<n-1;i++){ for(int j=0;j<n-1-i;j++){ if(data[j]-data[j+1]>0){ int temp=data[j]; data[j]=data[j+1]; data[j+1]=temp; } } } System.out.println("排序之後:\n"); System.out.println(java.util.Arrays.toString(data)); }
2:快速排序
(1)快速排序流程
——(1)首先設定一個分界值,通過該分界值將資料分成左右兩個部分。
——(2)將大於等於分界值的資料集中到陣列右邊,小於分界值的資料集中到陣列的左邊。
此時,左邊部分中的各元素都小於等於分界值,而右邊部分中各元素都大於等於分界值。
——(3)然後,左邊和右邊的資料可以獨立排序。對於左側的陣列資料,又可以取一個分界值,將該部分資料分成左右兩部分,
同樣將左邊放置較小值,右邊放置較大值。右邊的資料也做這樣的處理。
——(4)重複上述過程。
(2)快速排序程式碼分析
快速排序,平均O(nlogn),最壞O(n^2),空間O(logn),不穩定
時間效率:待排序序列本身已經有序或逆向有序時,快速排序的時間複雜度為Ο(n 2 ),
而在有序時插入排序的時間複雜度為Ο(n)。
空間效率:
(3)快速排序程式碼
public class AMoNiStack {
public static void main(String[] args){
AMoNiStack a=new AMoNiStack();
int[] b={1,4,5,32,7,54,2};
a.quicksort(b,0,b.length-1);
for(int i:b){
System.out.print(" "+i);
}
}
public void quicksort(int a[],int start,int end){
int i=start;
int j=end;
boolean flag=true;
if(i>=j){
return ;
}
while(i!=j){
if(a[i]>a[j]){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
flag=!flag;
}
if(flag){
j--;
}else{
i++;
}
}
i--;
j++;
quicksort(a,start,i);
quicksort(a,j,end);
}
}
二:選擇排序
1:簡單選擇排序
(1)選擇排序流程
——(1)首先從原始陣列中選擇最小的1個數據,將其和第一個位置的資料交換。
——(2)接著從剩下的n-1個數據中選擇次小的一個元素,將其和第二個位置的資料對換。
——(3)然後這樣不斷重複,直到最後兩個資料完成對換。至此,便完成了對原始陣列的從小到大的排序。
(2)選擇排序分析:
選擇排序在對n個數據執行的過程中,無論原資料是否有順序,都需要進行n-1步的中間排序。
優點:思路簡單
缺點:執行程式碼優點長,效率不是很高。
效率:時間複雜度O(n^2),空間效率,只需一個輔存空間
簡單選擇排序,平均O(n^2),最壞O(n^2),空間O(1),不穩定
(3)選擇排序程式碼
public class shuzuA {
static final int SIZE=10;
public static void main(String[] args){
int[] shuzu=new int[SIZE];
int i;
for(i=0;i<SIZE;i++){
shuzu[i]=(int)(100+Math.random()*(100+1));
}
System.out.println("排序前陣列:");
for(i=0;i<SIZE;i++){
System.out.print(shuzu[i]+" ");
}
System.out.println();
selectSort(shuzu);
System.out.println("排序後陣列:");
for(i=0;i<SIZE;i++){
System.out.print(shuzu[i]+" ");
}
}
public static void selectSort(int[] a){
int index,temp;
for(int i=0;i<a.length-1;i++){
index=i;
for(int j=i+1;j<a.length;j++){//為了找到index這個索引之後的最小值的索引。
if(a[j]<a[index]){
index=j;//每次比較完,index是最小值的索引。
}
}
if(index!=i){//交換兩個數
temp=a[i];
a[i]=a[index];
a[index]=temp;
}
}
}
}
2:堆排序(Heap Sort基於選擇排序思想的)
(1)堆排序流程
{什麼是堆結構:堆結構是一種樹結構,是一個完全二叉樹。}
(2)堆排序分析
堆排序,平均O(nlogn),最壞O(nlogn),空間O(1),不穩定
(3)堆排序程式碼
public class DemoJoin{
static final int SIZE=10;
static void heapSort(int a[],int n){
int i,j,h,k;
int t;
for(i=n/2-1;i>=0;i--){
while(2*i+1<n)
{
j=2*i+1;
if((j+1)<n){
if(a[j]<a[j+1])
j++;
}
if(a[i]<a[j])
{
t=a[i];
a[i]=a[j];
a[j]=t;
i=j;
}
else
break;
}
}
System.out.print("原資料構成的堆:");
for(h=0;h<n;h++)
System.out.print(" "+a[h]);
System.out.println();
for(i=n-1;i>0;i--){
t=a[0];
a[0]=a[i];
a[i]=t;
k=0;
while(2*k+1<i){
j=2*k+1;
if((j+1)<i)
{
if(a[j]<a[j+1])
j++;
}
if(a[k]<a[j])
{
t=a[k];
a[k]=a[j];
a[j]=t;
k=j;
}
else
break;
}
}
}
public static void main(String[] args) {
int[] shuzu=new int[SIZE];
int i;
for(i=0;i<SIZE;i++){
shuzu[i]=(int)(100+Math.random()*(100+1));
}
System.out.println("排序前的陣列:");
for(i=0;i<SIZE;i++){
System.out.print(shuzu[i]+" ");
}
System.out.println();
heapSort(shuzu,SIZE);
System.out.println("排序後的陣列:");
for(i=0;i<SIZE;i++){
System.out.print(shuzu[i]+" ");
}
System.out.println();
}
}
三:插入排序
1:直接插入排序(Insertion Sort)
(1)直接插入排序流程
——(1)首先對陣列的前兩個資料進行從小到大的排序。
——(2)接著將第3個數據與排好序的兩個資料比較,將第3個數據插入到何時的位置,
——(3)然後,將第四個資料插入到已排好序的前3個數據中。
——(4)不斷重複上述過程,直到把最後一個數據插入到合適的位置。最後,便完成了對原始資料從小到大的排序。
(打撲克,邊抓牌,邊捋牌)
(2)直接插入排序分析
插入排序演算法在對N個數據進行排序時,無論原陣列有無順序,都需要進行N-1步的排序。
優點:在陣列已有一定順序的情況下,排序效率較好。
缺點:如果資料無規則,則需要移動大量的資料。其排序效率也不是很好。
效率:時間複雜度O(n^2),並且是一個穩定的排序方法。
直接插入排序,平均O(n^2),最壞O(n^2),空間O(1),穩定性
(3)直接插入排序程式碼
public class shuzuA {
public static void main(String[] args){
int[] shuzu={1,234,42,344,5,3,9};
insertionSort(shuzu);
for(int i=0;i<shuzu.length;i++){
System.out.print(" "+shuzu[i]);
}
}
public static void insertionSort(int[] a){
int i;
int j;//需要插入的位置
int t;//要插入的資料
int h;
for(i=1;i<a.length;i++){
t=a[i];//要插入的資料是a[i],新抓的牌
j=i-1;//使需要插入的位置的在需要插入的元素的前一個
while(j>=0&&t<a[j]){
a[j+1]=a[j];
j--;
}
a[j+1]=t; //將資料t插入到正確的位置。
}
}
}
3:Shell排序(希爾排序/縮小增量排序)
(1)shell排序的流程
——(1)將有n個元素的陣列分為n/2個數字序列,第1個數據和第n/2+1個數據為一對,......
——(2)一次迴圈是每一個序列對排好順序
——(3)然後,在變為n/4個序列,在次排序
——(4)不斷重複上述過程,隨著序列減少最後變為一個,也就完成了整個排序。
(2)shell排序的分析
shell排序的時間複雜度是一個複雜的問題,因為shell排序的時間複雜度與步長序列有關。
(3)shell排序的程式碼
public class shuzuA {
public static void main(String[] args){
int[] shuzu={1,4,5,7,3,8,9,2};
System.out.print("原陣列為");
for(int h=0;h<shuzu.length;h++){
System.out.print(" "+shuzu[h]);
}
System.out.println();
shellSort(shuzu);
}
public static void shellSort(int[] a){
int i,j;
int r,temp;//r為間距
int x=0;
for(r=a.length/2;r>=1;r/=2){//將陣列元素分為多個數字序列
for(i=r;i<a.length;i++){
temp=a[i];
j=i-r;
while(j>=0&&temp<a[j]){
a[j+r]=a[j];
j-=r;
}
a[j+r]=temp;
}
x++;
System.out.print("第"+x+"步排序結果");
for(int h=0;h<a.length;h++){
System.out.print(" "+a[h]);
}
System.out.println();
}
}
}
四:合併排序(MergeSort)
(1)合併排序的流程(通過多次的二路合併完成一遍的合併)
——(1)將N個原始資料看成N個長度為1的有序字表,這時妹子字表中只有一個元素,
將他們一次兩兩合併,得到長度為2的若干有序字表
——(2)經過第1次合併,得到長度為2的有序表序列,在將長度為2的有序表序列進行兩
兩合併。得到長度為4的有序字表
——(3)不斷重複,一直到最後得到長度為N的有序字表,從而完成需過程。
(2)合併排序分析
合併排序,平均O(nlogn),最壞O(nlogn),空間O(n),穩定
(4)合併排序的程式碼
public class DemoJoin{ static final int SIZE=15; static void mergeOne(int a[],int b[],int n,int len) { int i,j,k,s,e; s=0; while(s+len<n) { e=s+2*len-1; if(e>=n) e=n-1; //相鄰有序段合併 k=s; i=s; j=s+len; while(i<s+len&&j<=e) { if(a[i]<=a[j]) b[k++]=a[i++]; else b[k++]=a[j++]; } while(i<s+len){ b[k++]=a[i++]; } while(j<=e) b[k++]=a[j++]; s=e+1; } if(s<n) { for(;s<n;s++) b[s]=a[s]; } } static void mergeSort(int a[],int n){ int h,count,len,f; count=0; len=1; f=0; int[] p=new int[n]; while(len<n){ if(f==1) mergeOne(p,a,n,len); else mergeOne(a,p,n,len); len=len*2; f=1-f; count++; System.out.printf("第"+count+"步排序結果"); for(h=0;h<SIZE;h++){ System.out.printf(" "+a[h]); } System.out.println(); } if(f==1){ for(h=0;h<n;h++){ a[h]=p[h]; } } } public static void main(String[] args) { int[] shuzu=new int[SIZE]; int i; for(i=0;i<SIZE;i++){ shuzu[i]=(int)(100+Math.random()*(100+1)); } System.out.println("排序前的陣列:"); for(i=0;i<SIZE;i++){ System.out.print(shuzu[i]+" "); } System.out.println(); mergeSort(shuzu,SIZE); System.out.println("排序後的陣列:"); for(i=0;i<SIZE;i++){ System.out.print(shuzu[i]+" "); } System.out.println(); } }