常見排序演算法及其實現(Binary,Insert、Select、Quick、Bubble.etc.Sort)

Guo_1_9發表於2018-03-06

常見排序演算法及其實現

說明

如果有幸能看到

  • 1、本文中的程式碼是參考《Java程式設計思想》、某培訓機構。
  • 2、文中的程式碼放Github了,有興趣的可以看看,點個star鼓勵下我。
  • 3、程式碼在Sublime中敲的,坑爹的GBK,註釋了很多中文,一轉碼不能用了!!!
  • 4、重點在思想,而不是實現 。再次推薦《Java程式設計思想》
  • 5、如有拼寫錯誤,還請諒解。本文只為自己複習使用,最後放了兩個收藏非常有水準的文章連結。

資料結構之排序

排序:假設含有n個記錄的序列{R1,R2,R3..,Rn},其中的關鍵字序列為{K1,K2,K3...,Kn}。將這些記錄重新排序為{Ri1,Ri2,Ri3,Rin} ,使得相應的關鍵字滿足Ki1<=Ki2<=..<=Kim,這樣的一種操作被稱為排序。

通常來說,排序的目的是快速查詢

衡量排序演算法的優勢:

  • 1、時間複雜度:分析關鍵字的比較次數和記錄的移動次數。
  • 2、空間複雜度:分析排序演算法中需要多少輔助記憶體。
  • 3、若兩個記錄A和B的關鍵字相等,但排序後A、B、的先後次序保持不變,則稱為這種排序演算法是穩定的。

排序演算法分類:內部排序和外部排序

  • 內部排序:整個排序過程不需要藉助於外部儲存器(如此攀等),整個排序在記憶體中完成。
  • 外部排序:參與排序的資料非常多,資料量非常大,計算機無法把整個排序過程放在記憶體中完成,必須藉助於外部儲存器,外部排序最常見的是多路歸併排序,可以認為外部排序由多次內部所組成。

常用的內部排序

  • 選擇排序
    • 直接選擇排序
    • 堆排序
  • 交換排序
    • 氣泡排序
    • 快速排序
  • 插入排序
    • 直接插入、折半插入
  • 歸併排序
  • 桶式排序
  • 基數排序

選擇排序

基本原理: 將待排序的元素分為已排序和未排序,依次將為排序的元素中最小的元素放入已排序的組中,

直接排序簡單直觀,但效能略差:堆排序是一種較為搞笑的選擇排序。但實現起來略為複雜。

常見排序演算法及其實現(Binary,Insert、Select、Quick、Bubble.etc.Sort)

程式碼實現:

import java.util.Arrays.*;
//選擇排序,
public class SelectSort{
	public static void selectSort(int[] data) {

		int arrayLength = data.length;
		for (int i = 0; i < arrayLength - 1 ; i++ ) {
			for (int j= i +1; j < arrayLength; j++ ) {
				if (data[i] > data[j]) {
					swap(data,i,j);
				}
			}
		}
		System.out.println("排序後 " + java.util.Arrays.toString(data));


	}

  //第一種通過臨時變數來完成交換
  //注意這裡可以用另外一中一種方式
	static void swap(int[] data,int i,int j) {
			int tmp = data[i];
			data[i] = data[j];
			data[j] = tmp;
		}


	public static void main(String[] args) {
		int[] data = {3,4,2,6,8,1,9};
		selectSort(data);
	}
}
複製程式碼

改進版的選擇排序:

//選擇排序演算法
//選擇排序演算法
//1、主要思想就是每次假設一個最小的值
public class SelectSort1 {
	public static void selectSort1(int[] data) {
		int arraylength = data.length;
		for (int i = 0; i < arraylength - 1; i++ ) {
			int minIndex = i;      //每次假設一個最小值下標
			for (int j = i + 1; j < arraylength ; j++ ) {
				if (data[minIndex] > data[j]) {
				minIndex = j;
				}
			}
			//判斷需要交換的下標是否為自己
			if (minIndex != i) {
				 data[minIndex] = data[minIndex] + data[i];
                 date[i] = date[minIndex] - data[i];
                 data[minIndex] = data[minIndex] - data[i];
			}

		}
		//輸出結果
		for (int d :data ) {
			System.out.println("排序之後:" + d);
		}
	}

	public static void main(String[] args) {
		int[] data = {3,4,2,6,8,1,9};
		selectSort1(data);
	}
}

複製程式碼

直接選擇排序效率分析

演算法的時間效率:無論初始化狀態如何,在第i趟排序中選擇最小的元素,需要n-1次比較

演算法的空間效率:空間效率較高,只需要一個附加程式單元用於交換,其空間效率為O(1)

演算法的穩定性:不穩定

堆排序

資料和程式碼來自這家,有一種感覺,年代越遠,越重視基礎。現在的培訓呢?

常見排序演算法及其實現(Binary,Insert、Select、Quick、Bubble.etc.Sort)

堆排序就是把最大堆堆頂的最大數取出,將剩餘的堆繼續調整為最大堆,再次將堆頂的最大數取出,這個過程持續到剩餘數只有一個時結束

  • 最大堆調整(Max-Heapify):將堆的末端子節點作調整,使得子節點永遠小於父節點
  • 建立最大堆(Build-Max-Heap):將堆所有資料重新排序,使其成為最大堆
  • 堆排序(Heap-Sort):移除位在第一個資料的根節點,並做最大堆調整的遞迴運算

這個有點難啊,下一個。回來再來看。

氣泡排序

相鄰兩元素進行比較,如有需要則進行交換,每完成一次迴圈就將最大元素排在前面(從小到大排序)下一次迴圈是將其他的數進行類似的比較。

程式碼實現:

//氣泡排序
public class BubbleSort {
	static void sort(int[] data) {
		int len = data.length;
		for (int i = 0; i < len - 1; i++ ) {
			for (int j = 0 ; j < len - 1 - i; j++ ) {
				if (data[j] > data[j + 1]) {
					swap(data,j,j+1);
				}
			}
		}

	}
	static void swap(int[] data,int i,int j) {
		int tmp = data[i];
		data[i] = data[j];
		data[j] = tmp;
	}

	public static void main(String[] args) {
		int[] data = {4,2,6,8,2,1,0};
		sort(data);
		for(int d : data) {
			System.out.print("->" + d);
		}
	}
}
複製程式碼

氣泡排序效率分析:

  • 演算法的時間效率:從氣泡排序的演算法可以看出,若待排序的元素為正序,則只需進行一趟排序,比較次數為n-1次,移動元素次數為0;若待排序的元素為逆序,則需要進行n-1趟排序.
  • 演算法的空間效率:空間效率很高,只需要一個附加程式單元用於交換,其空間效率為O(1)
  • 演算法的穩定性:穩定

快速排序

快速排序(Quick Sorting)基本思想是:任取待排序序列中的某個元素為界點,通過一次劃分,將待排序元素分為左右兩個子序列,左子序列元素的排列序列均小於界點元素的排序碼,右子序列的排序碼則大於或等於界點的排序碼,然後分別對兩個字序列繼續進行劃分,直至每一個序列只有一個元素為止。

一定要認真啊,認真啊,認真啊!!! 程式碼實現:

//快速排序
public class QuickSort {
	private static void swap(int[] data,int i,int j) {
		int tmp = data[i];
		data[i] = data[j];
		data[j] = tmp;
	}

	private static void subSort(int[] data,int start,int end) {
		if (start < end) {
		 int base = data[end];

		 int i = start;
		 int j = end + 1;

		 while(true) {
		 	while(i < end && data[++i] <= base) ;
		 	while(j > start && data[--j] >= base);
		 	if (i > j) {
		 		swap(data,i,j);
		 	}else {
		 		break;
			}
		}

			swap(data, start, j);
			subSort(data, start, j - 1);
			subSort(data, j + 1, end);
		}

	}
	public static void quickSort(int[] data) {
		subSort(data,0,data.length - 1);
	}

	public static void main(String[] args) {
		int[] data = {9,5,6,88};
		quickSort(data);
		System.out.print(java.util.Arrays.toString(data));
	}
}
複製程式碼

常見排序演算法及其實現(Binary,Insert、Select、Quick、Bubble.etc.Sort)

插入排序

基本思想:每次將一個待排序的元素,按其關鍵字的大小插入到前面已經排好序的子序的合適位置,直到全部記錄插入完成。

* 插入演算法.
* 1,從後向前找到合適的位置插入
* 基本思想:每步將一個待排序的記錄,按其順序碼大小插入到前面已經排好的子序列的合適位置
* 直到全部插入為止
*/
public class InsertSort {
   public static void main(String[] args) {
       //待排序的數列
       int[] nums = {43, 23, 64, 24, 34, 78, 32};
       //控制比較的輪數
       for (int i = 1; i < nums.length; i++) {
           //記錄運算元
           int temp = nums[i];
           int j = 0;
           for (j = i - 1; j >= 0; j--) {
               //後一個和前一個比較,如果前面的大,則把前面的賦值到後面。
               if (nums[j] > temp) {
                   nums[j+1] = nums[j];
               } else {
                   break;
               }
           }
           if (nums[j + 1] != temp) {
               nums[j + 1] = temp;
           }
       }
       //輸出結果
       for(int n : nums) {
           System.out.println(n);
       }
   }
}

複製程式碼

直接插入排序:

直接插入排序 的基本思想:把n個待排序的元素堪稱為一個有序表和無序表,開始時有序表中只包含一個元素,無序表中有n-1個元素,排序過程中每次從無序表中取出第一個元素的排序碼進行比較,將它插入到有序表中的適當位置,使之成為新的有序表。

程式碼實現:

//直接插入排序
public class InsertSort {
	public static void insertSort(int[] data) {
		int arrayLength = data.length;
		for (int i = 1; i < arrayLength; i++) {
			int tmp = data[i];

			if (data[i] < data[i -1]) {
				int j = i - 1;
				for (;j >=0 && data[j] > tmp; j-- ) {
					data[j + 1] = data[j];
				}
				data[j + 1] = tmp;
			}

		}
	}
	public static void main(String[] args) {
		int[] data = {5,2,6,9};
		insertSort(data);
		for (int d :data ) {
			System.out.print(" " + d);

		}
	}
}
複製程式碼

常見排序演算法及其實現(Binary,Insert、Select、Quick、Bubble.etc.Sort)

常見排序演算法及其實現(Binary,Insert、Select、Quick、Bubble.etc.Sort)

折半插入排序

  • 折半插入排序是對直接插入排序的簡單改進。
  • 此處介紹的折半插入,其實就是通過不斷地折半來快速確定第i個元素的插入位置,這實際上是一種查詢演算法:折半查詢。Java的Arrays類裡的binarySearch()方法,就是折半查詢的實現,用於從指定陣列中查詢指定元素,前提是該陣列已經處於有序狀態。
  • 與直接插入排序的效果相同,只是更快了一些,因為折半插入排序可以更快地確定第i個元素的插入位置

程式碼實現:

//折半插入排序
public class BinaryInsertSort{
	public static void binaryInsertSort(int[] data) {
		int len = data.length;
		for (int i = 1; i < len; i++) {
			int tmp = data[i];
			int low = 0;
			int high = i - 1;
			while(low <= high) {
				int mid = (low + high) / 2;
				if (tmp > data[mid]) {
					low = mid + 1;
				}
				else {
					high = mid -1;
				}

			}for (int j = i;j > low ; j-- ) {
				data[j] = data[j - 1 ];
			}
			data[low] = tmp;
		}
	}

	public static void main(String[] args) {
		int[] data = {5,2,7,3,9};
		binaryInsertSort(data);
		for (int d : data) {
			System.out.print(" " + d);
		}
	}
}
複製程式碼

常見排序演算法及其實現(Binary,Insert、Select、Quick、Bubble.etc.Sort)

/**
 * Created by guo on 2018/2/2.
 * 二分查詢法(折半查詢):前提是在已經排好序的陣列中,通過將待查詢的元素
 * 與中間索引值對應的元素進行比較,若大於中間索引值對應的元素,去右半邊查詢,
 * 否則,去左邊查詢。依次類推。直到找到位置;找不到返回一個負數
 */
public class BinarySearchSort {
    public static void main(String[] args) {
        //必須保證數列是有序的
        int[] nums = {12, 32, 55, 67, 87, 98};
        int i = binarySearch(nums, 87);
        System.out.println("查詢數的下標為:" + i);   //輸出下標為4
    }

    /**
     * 二分查詢演算法
     *
     * @param nums
     * @param key
     * @return
     */
    public static int binarySearch(int[] nums, int key) {
        int start = 0;             //開始下標
        int end = nums.length - 1; //結束下標
        while (start <= end) {     //開始位置不能穿過結束位置 --start-->|<--end--
            int middle = (start + end) / 2;
            // 如果查詢的key比中間的大,則去掉左邊的值
            if (key > nums[middle]) {
                start = middle + 1;
             //如果查詢的key比中間的小,則去掉右邊的。
            } else if (key < nums[middle]) {
                end = middle - 1;             //結束位置需要向前移一位。
            } else {
                return middle;
            }
        }
        //找不到則返回-1
        return -1;
    }
}
複製程式碼

先到這裡吧,後續還得多敲幾遍,需要學習的太多了,gogogo。

常見排序演算法及其實現(Binary,Insert、Select、Quick、Bubble.etc.Sort)

給大家放兩個連結,GitHubGitHub。裡面收集的文章非常有水準,點進去不會失望的。

相關文章