排序算法---基礎算法(冒泡排序,快速排序,選擇排序,直接插入排序,桶排序)

一:桶排序部分

使用條件:1.空間明確。2.對時間要求高

例子:一年的全國高考考生人數爲500 萬,分數使用標準分,最低100 ,最高900 ,沒有小數,要求對這500 萬元素的數組進行排序。

簡介:桶的個數固定,每一桶中統計這個數出現的次數

Code:

package sort;

import java.util.Arrays;

/**
 * @author MohnSnow
 * @time 2015年6月11日 上午9:40:07
 * @title 桶排序
 * 
 */
public class BucketSort {

	/**
	 * @param argsmengdx
	 *            -fnst
	 */
	//犧牲空間取代時間,必須知道數據範圍
	//時間複雜度:O(n2)  空間複雜度:O(m)
	public static int[] bucketSort(int[] a) {
		int[] b = new int[11];//表示取值範圍爲0~10  共十一個數字
		for (int i = 0; i < a.length; i++) {
			b[a[i]]++;
		}
		int temp = 0;
		for (int j = 0; j < b.length; j++) {
			if (b[j] > 0) {
				for (int m = 0; m < b[j]; m++) {
					a[temp++] = j;
				}
			}
		}
		return a;
	}

	public static void main(String[] args) {
		int[] a = { 1, 6, 5, 9, 6, 3, 10, 6, 9, 4, 3, 3 };
		System.out.println("數組a爲:" + Arrays.toString(a));
		System.out.println("桶排序:" + Arrays.toString(bucketSort(a)));
	}
}


二:冒泡排序部分

使用條件:1.每一次判斷出最大的那個。

簡介:兩兩比較,直到最大或最小出現在正確的位置上面

圖片:




Code:

package sort;

import java.util.Arrays;

/**
 * @author MohnSnow
 * @time 2015年6月11日 上午9:04:27
 * @title 冒泡排序
 * 
 */
public class BubbleSort {

	/**
	 * @param argsmengdx
	 *            -fnst
	 */
	//犧牲時間代替空間,與桶排序是兩個極端
	//時間複雜度:O(n2)  空間複雜度:O(1)
	public static int[] bubbleSort(int[] a) {
		int len = a.length;
		int temp;
		for (int i = 0; i < len; i++) {
			for (int j = 0; j < len - 1; j++) {
				if (a[j] > a[j + 1]) {
					temp = a[j];
					a[j] = a[j + 1];
					a[j + 1] = temp;
				}
			}
		}
		return a;
	}

	public static int[] bubbleSort1(int[] a) {
		int len = a.length;
		int temp;
		for (int i = 0; i < len; i++) {
			for (int j = 0; j < len - 1 - i; j++) {//因爲一次排序已經有序了,可以省略比較排序好的序列  :j < len - 1 - i
				if (a[j] > a[j + 1]) {
					temp = a[j];
					a[j] = a[j + 1];
					a[j + 1] = temp;
				}
			}
		}
		return a;
	}

	public static void main(String[] args) {
		int[] a = { 1, 6, 5, 9, 6, 3, 10, 6, 9, 4, 3, 3 };
		System.out.println("數組a爲:" + Arrays.toString(a));
		//System.out.println("冒泡排序:" + Arrays.toString(bubbleSort(a)));
		System.out.println("冒泡排序1:" + Arrays.toString(bubbleSort1(a)));
	}

}


三:選擇排序部分

工作原理:是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的數據元素排完。 選擇排序是不穩定的排序方法(比如序列[5, 5, 3]第一次就將第一個[5]與[3]交換,導致第一個5挪動到第二個5後面)。

Code:

package sort;

import java.util.Arrays;

/**
 * @author MohnSnow
 * @time 2015年6月11日 上午11:09:35
 * @title 選擇排序
 * 
 */
public class SelectionSort {

	/**
	 * @param argsmengdx
	 *            -fnst
	 */
	//每次選取最小的數字放到前面
	public static int[] selectSort(int[] a) {
		int len = a.length;
		int temp, k;
		for (int i = 0; i < len - 1; i++) {//之所以選取i<len-1是因爲最後剩下一個數肯定是最大的。
			k = i;
			for (int j = i + 1; j < len; j++) {
				if (a[j] < a[k]) {
					k = j;
				}
			}
			temp = a[i];
			a[i] = a[k];
			a[k] = temp;
			System.out.println("i的值爲:" + i + "打印每次排序結果爲:" + Arrays.toString(a));
		}
		return a;
	}
	
	public static void main(String[] args) {
		int[] a = { 1, 6, 5, 9, 6, 3, 10, 6, 9, 4, 3, 3 };
		System.out.println("數組a爲:" + Arrays.toString(a));
		System.out.println("選擇排序爲:" + Arrays.toString(selectSort(a)));
	}

}


四:直接插入排序算法

簡介:把序列分爲已排序和未排序部分,假設前面的序列是有序的,然後選擇數據有序數列插入。

Code:

package sort;

import java.util.Arrays;

/**
 * @author MohnSnow
 * @time 2015年6月11日 下午1:58:45
 * @title 直接插入排序
 * 
 */
public class StraightInsertionSort {

	/**
	 * @param argsmengdx
	 *            -fnst
	 */
	public static int[] straightInsertionSort(int[] a) {
		int len = a.length;
		int iValue, i, j;
		for (i = 1; i < len; i++) {
			iValue = a[i];
			j = i - 1;
			while (j >= 0 && iValue < a[j]) {//a[i] < a[j] 一開始寫錯了,應該有一個temp去存取這個值
				a[j + 1] = a[j];
				j--;
			}
			a[j + 1] = iValue;
			System.out.println("打印每次排序結果爲:" + Arrays.toString(a));
		}
		return a;
	}

	public static void main(String[] args) {
		int[] a = { 1, 6, 5, 9, 6, 3, 10, 6, 9, 4, 3, 3, 1 };
		int[] b = { 4, 3, 2, 1 };
		int[] c = { 1, 2, 3, 4 };
		int[] d = { 4, 3, 2 };
		System.out.println("數組a爲:" + Arrays.toString(a));
		System.out.println("數組b爲:" + Arrays.toString(b));
		System.out.println("數組c爲:" + Arrays.toString(c));
		System.out.println("數組d爲:" + Arrays.toString(d));
		System.out.println("直接插入排序:" + Arrays.toString(straightInsertionSort(a)));
	}

}


五:快速排序部分

該方法的基本思想是:

1.先從數列中取出一個數作爲基準數。

2.分區過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。

3.再對左右區間重複第二步,直到各區間只有一個數。

4.注意是先進行減法,後進行加法。

簡介:選取一個哨兵

Code:

package sort;

import java.util.Arrays;

/**
 * @author MohnSnow
 * @time 2015年6月11日 上午9:56:31
 * 
 */
public class QuickSort {

	/**
	 * @param argsmengdx
	 *            -fnst
	 */
	//時間複雜度:O(n*logn)  空間複雜度:O(1)
	public static int[] quickSort(int[] a) {
		subQuickSort(a, 0, a.length - 1);
		return a;
	}

	public static void subQuickSort(int[] a, int begin, int end) {
		int temp_begin = begin;
		int temp_end = end;
		int temp;
		if (begin == end || begin < 0 || end > a.length - 1) {
			return;
		}
		if (end - begin == 1) {
			if (a[end] < a[begin]) {
				temp = a[begin];
				a[begin] = a[end];
				a[end] = temp;
			}
			return;
		}
		int guard = begin++;
		while (begin < end) {//找中間點過程單獨寫個方法去處理
			while (a[end] >= a[guard] && end != begin) {
				end--;
			}
			while (a[begin] < a[guard] && end != begin) {
				begin++;
			}
			if (end == begin) {
				break;
			} else {
				temp = a[end];
				a[end] = a[begin];
				a[begin] = temp;
			}
		}
		if (begin == temp_begin + 1) {//位於第一個,例如,3133
			if (a[begin] < a[guard]) {//轉換條件可以單獨寫個方法
				temp = a[guard];
				a[guard] = a[begin];
				a[begin] = temp;
			}
			subQuickSort(a, temp_begin + 1, temp_end);
		} else if (begin == temp_end) {//位於最後一個 ,例如:5234
			if (a[begin] < a[guard]) {
				temp = a[guard];
				a[guard] = a[begin];
				a[begin] = temp;
			}
			subQuickSort(a, temp_begin, temp_end - 1);
		} else {//位於中間
			if (a[begin] < a[guard]) {
				temp = a[guard];
				a[guard] = a[begin];
				a[begin] = temp;
			}
			subQuickSort(a, temp_begin, begin - 1);
			subQuickSort(a, begin + 1, temp_end);
		}
	}

	public static void main(String[] args) {
		int[] a = { 1, 6, 5, 9, 6, 3, 10, 6, 9, 4, 3, 3, 1 };
		int[] b = { 4, 3, 2, 1 };
		int[] c = { 1, 2, 3, 4 };
		System.out.println("數組a爲:" + Arrays.toString(a));
		System.out.println("數組b爲:" + Arrays.toString(b));
		System.out.println("數組c爲:" + Arrays.toString(c));
		//Arrays.sort(b);
		//System.out.println("快速排序b:" + Arrays.toString(b));
		System.out.println("快速排序:" + Arrays.toString(quickSort(a)));
	}

}

五:希爾排序部分

參考:http://blog.csdn.net/morewindows/article/details/6668714

基本思想是:先將整個待排元素序列分割成若干個子序列(由相隔某個“增量”的元素組成的)分別進行直接插入排序,然後依次縮減增量再進行排序,待整個序列中的元素基本有序(增量足夠小)時,再對全體元素進行一次直接插入排序。因爲直接插入排序在元素基本有序的情況下(接近最好情況),效率是很高的,因此希爾排序在時間效率上比前兩種方法有較大提高。

void shellsort1(int a[], int n)
{
	int i, j, gap;

	for (gap = n / 2; gap > 0; gap /= 2) //步長
		for (i = 0; i < gap; i++)        //直接插入排序
		{
			for (j = i + gap; j < n; j += gap) 
				if (a[j] < a[j - gap])
				{
					int temp = a[j];
					int k = j - gap;
					while (k >= 0 && a[k] > temp)
					{
						a[k + gap] = a[k];
						k -= gap;
					}
					a[k + gap] = temp;
				}
		}
}


六:歸併排序部分(分治法)

參考:http://blog.csdn.net/morewindows/article/details/6678165

算法思想:歸併排序是建立在歸併操作上的一種有效的排序算法。該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。首先考慮下如何將將二個有序數列合併。這個非常簡單,只要從比較二個數列的第一個數,誰小就先取誰,取了後就在對應數列中刪除這個數。然後再進行比較,如果有數列爲空,那直接將另一個數列的數據依次取出即可。其的基本思路就是將數組分成二組A,B,如果這二組組內的數據都是有序的,那麼就可以很方便的將這二組數據進行排序

//將有二個有序數列a[first...mid]和a[mid...last]合併。
void mergearray(int a[], int first, int mid, int last, int temp[])
{
	int i = first, j = mid + 1;
	int m = mid,   n = last;
	int k = 0;
	
	while (i <= m && j <= n)
	{
		if (a[i] <= a[j])
			temp[k++] = a[i++];
		else
			temp[k++] = a[j++];
	}
	
	while (i <= m)
		temp[k++] = a[i++];
	
	while (j <= n)
		temp[k++] = a[j++];
	
	for (i = 0; i < k; i++)
		a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
	if (first < last)
	{
		int mid = (first + last) / 2;
		mergesort(a, first, mid, temp);    //左邊有序
		mergesort(a, mid + 1, last, temp); //右邊有序
		mergearray(a, first, mid, last, temp); //再將二個有序數列合併
	}
}

bool MergeSort(int a[], int n)
{
	int *p = new int[n];
	if (p == NULL)
		return false;
	mergesort(a, 0, n - 1, p);
	delete[] p;
	return true;
}


七:堆排序部分

參考:http://blog.csdn.net/morewindows/article/details/6709644

二叉堆的定義

二叉堆是完全二叉樹或者是近似完全二叉樹。

二叉堆滿足二個特性:

1.父結點的鍵值總是大於或等於(小於或等於)任何一個子節點的鍵值。

2.每個結點的左子樹和右子樹都是一個二叉堆(都是最大堆或最小堆)。

//  新加入i結點  其父結點爲(i - 1) / 2
void MinHeapFixup(int a[], int i)
{
    int j, temp;
	
	temp = a[i];
	j = (i - 1) / 2;      //父結點
	while (j >= 0 && i != 0)
	{
		if (a[j] <= temp)
			break;
		
		a[i] = a[j];     //把較大的子結點往下移動,替換它的子結點
		i = j;
		j = (i - 1) / 2;
	}
	a[i] = temp;
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章