public class ArraySort {
/**
* 選擇排序<br/>
* <li>在未排序序列中找到最小元素,存放到排序序列的起始位置</li>
* <li>再從剩餘未排序元素中繼續尋找最小元素,然後放到排序序列末尾。</li>
* <li>以此類推,直到所有元素均排序完畢。</li>
*
* @param numbers
*/
public static void selectSort(int[] numbers) {
int size = numbers.length, temp;
for (int i = 0; i < size; i++) {
int k = i;
for (int j = size - 1; j > i; j--) {
if (numbers[j] > numbers[k]) k = j;
}
temp = numbers[i];
numbers[i] = numbers[k];
numbers[k] = temp;
}
}
/**
* 冒泡法排序<br/>
* <p>
* <li>比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。</li>
* <li>對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。</li>
* <li>針對所有的元素重複以上的步驟,除了最後一個。</li>
* <li>持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。</li>
*
* @param numbers 需要排序的整型數組
*/
public static void bubbleSort(int[] numbers) {
int temp; // 記錄臨時中間值
int size = numbers.length; // 數組大小
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < size; j++) {
if (numbers[i] < numbers[j]) { // 交換兩數的位置
temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
}
}
}
/**
* 快速排序<br/>
* <ul>
* <li>從數列中挑出一個元素,稱爲“基準”</li>
* <li>重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)
* 。在這個分割之後, 該基準是它的最後位置。這個稱爲分割(partition)操作。</li>
* <li>遞歸地把小於基準值元素的子數列和大於基準值元素的子數列排序。</li>
* </ul>
*
* @param numbers
* @param start
* @param end
*/
public static void quickSort(int[] numbers, int start, int end) {
//如果left等於right,即數組只有一個元素,直接返回
if(start>=end) {
return;
}
//設置最左邊的元素爲基準值
int key=numbers[start];
//數組中比key小的放在左邊,比key大的放在右邊,key值下標爲i
int i=start;
int j=end;
while(i<j){
//j向左移,直到遇到比key小的值
while(numbers[j]>=key && i<j){
j--;
}
//i向右移,直到遇到比key大的值
while(numbers[i]<=key && i<j){
i++;
}
//i和j指向的元素交換
if(i<j){
int temp=numbers[i];
numbers[i]=numbers[j];
numbers[j]=temp;
}
}
numbers[start]=numbers[i];
numbers[i]=key;
quickSort(numbers,start,i-1);
quickSort(numbers,i+1,end);
}
/**
* 插入排序
* <p>
* 從第一個元素開始,該元素可以認爲已經被排序
* 取出下一個元素,在已經排序的元素序列中從後向前掃描
* 如果該元素(已排序)大於新元素,將該元素移到下一位置
* 重複步驟3,直到找到已排序的元素小於或者等於新元素的位置
* 將新元素插入到該位置中
* 重複步驟2
*
* @param numbers
*/
public static void insertSort(int[] numbers) {
int size = numbers.length, temp, j;
for (int i = 1; i < size; i++) {
temp = numbers[i];
for (j = i; j > 0 && temp < numbers[j - 1]; j--)
numbers[j] = numbers[j - 1];
numbers[j] = temp;
}
}
/**
* 歸併排序
* <p>
* 申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
* 設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
* 比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
* 重複步驟3直到某一指針達到序列尾
* 將另一序列剩下的所有元素直接複製到合併序列尾
*
*/
public static void mergeSort(int a[],int start,int end){
if (a!=null && end>start){
int mid = (end + start) / 2;
mergeSort(a,start,mid);
mergeSort(a,mid+1,end);
merge(a,start,mid,end);
}
}
private static void merge(int a[], int start, int mid, int end){
int tmp[] = new int[end-start+1];
int i = start;
int j = mid+1;
int k = 0;
while (i<= mid &&j<=end ){
if(a[i]<=a[j])tmp[k++]=a[i++];
else tmp[k++]=a[j++];
}
while (i<=mid)tmp[k++]=a[i++];
while (j<=end)tmp[k++]=a[j++];
for (i = 0;i<k;i++){
a[start+i]=tmp[i];
}
}
/**
* 希爾排序算法
* 基本思想:先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,待整個序列
* 中的記錄“基本有序”時,再對全體記錄進行依次直接插入排序
*
* @param a
*/
public static void shellSort(int[] a) {
int dk = a.length / 2;
while (dk >= 1) {
ShellInsertSort(a, dk);
dk = dk / 2;
}
}
private static void ShellInsertSort(int[] a, int dk) {
//類似插入排序,只是插入排序增量是 1,這裏增量是 dk,把 1 換成 dk 就可以了
for (int i = dk; i < a.length; i++) {
if (a[i] < a[i - dk]) {
int j;
int x = a[i];//x 爲待插入元素
a[i] = a[i - dk];
for (j = i - dk; j >= 0 && x < a[j]; j = j - dk) {
//通過循環,逐個後移一位找到要插入的位置。
a[j + dk] = a[j];
}
a[j + dk] = x;//插入
}
}
}
/**
* 堆排序
* @param nums 待排序數組序列
* @return 排好序的數組序列
*/
public static int[] heapSort(int[] nums) {
for (int i = nums.length / 2 - 1; i >= 0; i--) {
heapAdjust(nums, i, nums.length);
}
for (int i = nums.length - 1; i > 0; i--) {
int temp = nums[i];
nums[i] = nums[0];
nums[0] = temp;
heapAdjust(nums, 0, i);
}
return nums;
}
/**
* 調整堆
*
* @param nums 待排序序列
* @param parent 待調整根節點
* @param length 數組序列長度
*/
private static void heapAdjust(int[] nums, int parent, int length) {
int temp = nums[parent];
int childIndex = 2 * parent + 1; //完全二叉樹節點i從編號1開始的左子節點位置在2i,此處數組下標從0開始,即左子節點所在數組索引位置爲:2i + 1
while (childIndex < length) {
if (childIndex + 1 < length && nums[childIndex] < nums[childIndex + 1]) {
childIndex++; //節點有右子節點,且右子節點大於左子節點,則選取右子節點
}
if (temp > nums[childIndex]) {
break; //如果選中節點大於其子節點,直接返回
}
nums[parent] = nums[childIndex];
parent = childIndex;
childIndex = 2 * parent + 1; //繼續向下調整
}
nums[parent] = temp;
}
}