1. 程式人生 > >各種排序演算法大合集

各種排序演算法大合集

各種演算法的比較: 在這裡插入圖片描述 快速排序: 在這裡插入圖片描述

希爾(Shell)排序: 要點 希爾(Shell)排序又稱為縮小增量排序,它是一種插入排序。它是直接插入排序演算法的一種威力加強版。

希爾排序的基本思想是:

把記錄按步長 gap 分組,對每組記錄採用直接插入排序方法進行排序。 隨著步長逐漸減小,所分成的組包含的記錄越來越多,當步長的值減小到 1 時,整個資料合成為一組,構成一組有序記錄,則完成排序。

我們來通過演示圖,更深入的理解一下這個過程。

在上面這幅圖中: 在這裡插入圖片描述

初始時,有一個大小為 10的無序序列。

在第一趟排序中,我們不妨設 gap1 = N / 2 = 5,即相隔距離為 5 的元素組成一組,可以分為 5 組。

接下來,按照直接插入排序的方法對每個組進行排序。

在第二趟排序中,我們把上次的 gap縮小一半,即 gap2 = gap1 / 2 = 2 (取整數)。這樣每相隔距離為 2的元素組成一組,可以分為 2 組。

按照直接插入排序的方法對每個組進行排序。

在第三趟排序中,再次把 gap縮小一半,即gap3 = gap2 / 2 = 1。這樣相隔距離為 1 的元素組成一組,即只有一組。

按照直接插入排序的方法對每個組進行排序。此時,排序已經結束。

需要注意一下的是,圖中有兩個相等數值的元素 5 和 5 。我們可以清楚的看到,在排序過程中,兩個元素位置交換了。

所以,希爾排序是不穩定的演算法。

朕的實現方法在此:

//測試類:
//注意:com.sxt.xxx 是包名
package org.sxt.test;

import java.util.Arrays;
import java.util.Scanner;

import com.sxt.b.BubbleSort;
import com.sxt.b.InsertSort;
import com.sxt.b.MergeSort;
import com.sxt.b.QuickSort;
import com.sxt.b.SelectSort;
import com.sxt.b.ShellSort;
import com.sxt.win.Show;

public class TestSort {

	public static void main(String[] args) {
		//1.給出無序陣列
		int arr[]= {72,6,57,88,60,42,83,73,48,85};
		//2.輸出無序陣列
		System.out.println("原陣列:"+Arrays.toString(arr));
		
		while(true) {
	     //3.排序
        Show.show();
		Scanner sc = new Scanner(System.in);
		int select = sc.nextInt();
		switch(select)
		{
		   case 1:QuickSort.quickSort(arr);break;
		   case 2:BubbleSort.bulleSort(arr);break;
		   case 3:SelectSort.select(arr);break;
		   case 4:InsertSort.insertSort(arr);break;
		   case 5:ShellSort.shellSort(arr);break;
		   case 6:MergeSort.merge_sort(arr);break;
		}
		//4.輸出有序數列
        System.out.println(Arrays.toString(arr));
	  }
	}

}

package com.sxt.win;


public class Show {
	public static void show() {
		System.out.println("請選擇排序方式:\n1.快速排序\n2.氣泡排序\n3.選擇排序\n4.插入排序\n5.希爾遍歷\n6.歸併排序");
	}
}
//氣泡排序
package com.sxt.b;

public class BubbleSort {
	//氣泡排序演算法
	public static void bulleSort(int[] arr) {
		for(int i=0;i<arr.length-1;i++)//掃描次數
		{
			for(int j=0;j<arr.length-1-i;j++) {
				if(arr[j]>arr[j+1]) {
					int temp=arr[j];
				    arr[j]=arr[j+1];
				    arr[j+1]=temp;
				}
			}
		}
		
	}
}

//插入排序
package com.sxt.b;

public class InsertSort {
	public static void insertSort(int[] arr) {
		/*遍歷所有的數字看哪個比前面的小,
        *如果小那就說明前面至少有一個比當前元素小的
        *把當前元素塞到剛好比當前元素的小的元素前面,那麼它後邊的都要往後排一個
        */		
		for(int i=1;i<arr.length;i++) {
			//如果當前數字比前一個數字小
			if(arr[i]<arr[i-1]) {
				//先把當前元素存起來
				int temp=arr[i];
				//遍歷當前元素前面的元素
				for(int j=i-1;j>0&&temp<arr[j];j--) {
					//把前一個數字賦給後一個數字
					arr[j+1]=temp;
				}
			}
		}
	}

}

//歸併排序
package com.sxt.b;

public class MergeSort {
	public static void merge_sort(int[] arr) {
		  mergesort(arr, 0, arr.length - 1);
		}
		public static void mergesort(int[] arr,int left, int right) {
		  if(left < right) return;  
		  int middle = (left+right) / 2;
		  mergesort(arr, left, middle);
		  mergesort(arr, middle + 1, right);
		  mergeArr(arr, left, middle, right);//將左右兩部分合並(左右兩部分已經在遞迴中各自排好了序)
		}
		public static void mergeArr(int[] arr, int left, int middle, int right) {
		  int[] temp = new int[right - left + 1];//開闢新陣列
		  int i = left, j = middle + 1, k = 0;
		  while(i <= middle && j <= right) {//經過這個迴圈後最多有一個數組有殘餘
		    temp[k++] = arr[i] < arr[j]? arr[i++] : arr[j++];
		  }
		  while(i <= middle) {//如果有殘餘加入到temp中
		    temp[k++] = arr[i++];
		  }
		  while(j <= right) {//如果有殘餘加入到temp中
		    temp[k++] = arr[j++];
		  }
		  // 將輔助陣列資料寫入原陣列
		  int index = 0;
		  while(left <= right) {
		    arr[left++] = temp[index++];
		  }
		}
}

//快速排序
package com.sxt.b;
public class QuickSort {
	//分割槽函式
	private static int partition(int[] arr,int low,int high) {
		//1.指定左指標i和右針織j
		int i=low;
		int j=high;
		//2.將第一個元素作為基準,挖坑帶走
		int x=arr[low];
		//3.使用迴圈實現分割槽操作
        while(i<j) {
        	//1.從右至左移動j,找到第一個小於基準值的元素,arr[j],挖走
        	while(arr[j]>x&&i<j) {
        		j--;
        	}
        	//2.將arr[j]填入左邊坑的位置,左指標i向右移動一個單位,指標右移一位i++
        	if(i<j) {
        		arr[i]=arr[j];
        		i++;
        	}
        	//3.從左向右移動i,找到第一個大於基準的元素arr[i]
        	while(arr[i]<x&&i<j) {
        		i++;
        	}       	
        	//4.將左側找到的元素填入到右邊的坑內,j--
        	if(i<j) {
        		arr[j]=arr[i];
        		j--;
        	}
        }
		//4.使用基準填坑,這是基準值的最終位置
		arr[i]=x;
		//5.返回基準的位置、
		return i;
	}
	//快速排序演算法
	private static void quickSort(int[] arr,int low, int high) {//遞迴何時結束(low<high),所剩元素大於兩個
		if(low<high) {
		//分割槽操作,將一個數組分成兩個分割槽,並返回分割槽索引
		int index=partition(arr,low,high);
		//將左分割槽進行快排
		quickSort(arr,low,index-1);
		//將右分割槽進行快排
		quickSort(arr,index+1,high);
	}
}
	public static void quickSort(int[] arr) {
		int low=0;
		int high=arr.length-1;
		quickSort(arr,low,high);
	}
}

//選擇排序
package com.sxt.b;

public class SelectSort {
	public static void select(int[] arr) {
		for(int i=0;i<arr.length-1;i++)
			for(int j=i+1;j<arr.length;j++)
			{
				if(arr[i]>arr[j])
				{
					int temp=arr[i];
					arr[i]=arr[j];
					arr[j]=temp;
				}
			}
	}
    
}

//希爾排序
package com.sxt.b;

import java.util.Arrays;

public class ShellSort {
	public static void shellSort(int[] arr) {
		int k=0;
		//遍歷所有的步長(步長每次減半)
		for(int d=arr.length/2;d>0;d/=2)
		{
			//遍歷所有組
			for(int i=d;i<arr.length;i++) {
				//遍歷本組中的元素(相隔為d的元素是一組)
				for(int j=i-d;j>=0;j-=d)
				{
					//如果當前元素大於加上步長後的元素則交換位置
					if(arr[j]>arr[j+d]) {
						int temp=arr[j];
						arr[j]=arr[j+d];
						arr[j+d]=temp;
					}
				}
			}
			k++;
			System.out.println("第"+k+"次步長折半遍歷"+Arrays.toString(arr));
		}
	}

}