go實現常見排序算法

排序算法

代碼地址

對十萬個隨機數進行排序

排序算法的穩定性和排序算法分類

排序算法的穩定性:能保證兩個相等的值,在排序前他們的相對位置不變,即a[0]=3,a[5]=3,如果排序後能保證a[0]的3在a[5]的3的前面就是穩定的算法;

常見排序算法
交換排序
選擇排序
插入排序
歸併排序
冒泡排序
快速排序
選擇排序
堆排序
直接插入排序
希爾排序
基數排序

交換排序

冒泡排序算法思想

冒泡排序,就像它的名字一樣,像氣泡慢慢的浮到水面上;冒泡排序中每個數就像是一個氣泡,氣泡浮到水面上的過程就是冒泡排序的比較,冒泡排序就是通過相鄰兩個數字進行比較,滿足a>b或者b>a就交換他們的位置,一直到浮出”水面“

冒泡排序1

func Sbubble1(ans []int) {
	ansLen := len(ans)
	for i := 0; i < ansLen; i++ {
		for j := 0; j < ansLen-1-i; j++ {
			if ans[j] > ans[j+1] {
				ans[j], ans[j+1] = ans[j+1], ans[j]
			}
		}
	}
	fmt.Printf("冒泡排序:%d個隨機數\n", ansLen)
}

冒泡排序2

這種冒泡排序是對冒泡排序進行了優化,添加一個局部變量來記錄冒泡排序每一輪有沒有交換,如果沒有交換,那麼所有的數都已經是有序的了,也就沒有必要進行比較了,直接終止循環。

func Sbubble2(ans []int) {
	ansLen := len(ans)
	flag := true
	for i := 0; i < ansLen && flag; i++ {
		flag = false
		for j := 0; j < ansLen-1-i; j++ {
			if ans[j] > ans[j+1] {
				ans[j], ans[j+1] = ans[j+1], ans[j]
				flag = true
				//ExportArray(&ans)
			}
		}
	}
	fmt.Printf("冒泡排序:%d個隨機數\n", ansLen)
}

快速排序

快速排序的思路很簡單,就是取一個樞紐,比它大的數放到右邊,比它小的數放到左邊,然後利用分治的思想,一直這樣分,最終實現排序

func QuickSort(ans []int, low, high int) {
	if low < high {
		pivot := partition(ans, low, high)
		QuickSort(ans, low, pivot-1)
		QuickSort(ans, pivot+1, high)
	}
}

func partition(ans []int, low, high int) int {
	pivot := ans[low]
	for low < high {
		for ; low < high && ans[high] >= pivot; high-- {
		}
		ans[low] = ans[high]
		for ; low < high && ans[low] <= pivot; low++ {
		}
		ans[high] = ans[low]
	}
	ans[low] = pivot
	return low
}

選擇排序

算法思想

選擇排序,其核心就是選擇的過程,選擇的過程就是選擇出最大或者最小的數,如果是n個數的話,就要進行n-1輪比較,最終實現排序的過程;具體的過程就是從第i個數開始,跟第i+1...n-1個數進行比較,找到最大或者最小的數,那就和第i個數交換位置

選擇排序

func Selection(ans []int) {
	ansLen := len(ans)
	for i := 0; i < ansLen-1; i++ {
		minpos := i
		for j := i + 1; j < ansLen; j++ {
			if ans[j] < ans[minpos] {
				minpos = j
			}
		}
		if minpos != i {
			ans[minpos], ans[i] = ans[i], ans[minpos]
		}
	}
}

堆排序

堆排序,其實就是一個完全二叉樹,堆分爲大頂堆和小頂堆,大頂堆就是每個節點都大於或者等於其子樹的每個節點,小頂堆就是每個子樹都小於或者等於其子樹的每個節點。堆排序的過程也就是調整的過程,通過一次次的調整,調整出最大或者最小的值,最終通過n-1次調整最終調整出有序的序列;首先,調整就是從最後一個非葉子節點開始,比較它的左右子樹,如果小於子樹,就交換它們,這個時候可能會打亂原來已經調整好的順序,這個時候就要從被交換的那個子樹開始繼續調整。

func HeapSort(ans []int) {
	ansLen := len(ans)
	for i := ansLen/2 - 1; i >= 0; i-- {
		adjustHeap(ans, i, ansLen)
	}
	for j := ansLen - 1; j > 0; j-- {
		ans[0], ans[j] = ans[j], ans[0]
		adjustHeap(ans, 0, j)
	}
	fmt.Printf("堆排序:%d個隨機數\n", ansLen)
}

func adjustHeap(ans []int, i, length int) {
	pos := i
	for k := 2*i + 1; k < length; k = 2*k + 1 {
		if k+1 < length && ans[k] < ans[k+1] {
			k++
		}
		if ans[k] > ans[pos] {
			ans[k], ans[pos] = ans[pos], ans[k]
			pos = k
		} else {
			break
		}
	}
}

插入排序

直接插入排序

就是把序列分爲兩部分,左邊是已經有序的,右邊是無序的,每次取出一個無序的數a,如果是從小到大的順序排列的話,就是從有序序列的最後一個開始比較如果比a大,那麼就和a交換,a繼續和它的上一個數比較,直到找到比a小的數結束。然後繼續從無序序列開始取數,重複操作,直到把無序序列全部取完,這就完成排序了。

func Sinsert(ans []int) {
	ansLen := len(ans)
	for i := 1; i < ansLen; i++ {
		for j := i - 1; j >= 0; j-- {
			if ans[j+1] < ans[j] {
				ans[j+1], ans[j] = ans[j], ans[j+1]
			} else {
				//ExportArray(&ans)
				break
			}
		}
	}
	fmt.Printf("直接插入排序:%d個隨機數\n", ansLen)
}

希爾排序

希爾排序的的基本思想是:先將整個待排序的記錄序列分割成若干子序列,分別進行直接插入排序,待整個序列中的記錄基本有序時,再對全體記錄進行一次直接插入排序

func Shellsort(ans []int) {
	ansLen := len(ans)
	for increment := ansLen / 2; increment >= 1; increment = increment / 2 {
		for i := increment; i < ansLen; i++ {
			for j := i - increment; j >= 0 && ans[j] > ans[j+increment]; j -= increment {
				ans[j], ans[j+increment] = ans[j+increment], ans[j]
				//ExportArray(&ans)
			}
		}
	}
	fmt.Printf("希爾排序:%d個隨機數\n", ansLen)
}

歸併排序

歸併排序算就是一個最直接的分治算法,這裏就按2路歸併講吧,就是把序列分成2個一組,如果多出一個直接成爲一組,每組2個數進行比較排序,每個子序列都有序後,然後兩兩合併,最後合併成一個有序序列,就完成了排序

func MergeSort(ans []int) []int {
	ansLen := len(ans)
	if ansLen < 2 {
		return ans
	}
	left := ans[0:(ansLen / 2)]
	right := ans[(ansLen/2 + 1):]
	return merge(MergeSort(left), MergeSort(right))
}

func merge(left []int, right []int) []int {
	var res []int
	for len(left) != 0 && len(right) != 0 {
		if left[0] <= right[0] {
			res = append(res, left[0])
			left = left[1:]
		} else {
			res = append(res, right[0])
			right = right[1:]
		}
	}
	for len(left) != 0 {
		res = append(res, left[0])
		left = left[1:]
	}
	for len(right) != 0 {
		res = append(res, right[0])
		right = right[1:]
	}
	return res
}

基數排序

基數排序,就是從個位,十位,百位….一直到最高位,比如個位爲1的都放到bucket[1]裏面依次類推,當所有的數都放到各自桶裏後,然後開始從0號桶中取出所有的數,然後重複操作取十位,百位,等等,直到取到最高位,最後取出來後所有的數都是有序的了

func RadixSort(ans []int) {
	length := getMaxNumLen(ans)
	mod := 10
	for i := 1; i <= length; i++ {
		tmp := setBucket(ans, mod)
		mod *= 10
		getArray(tmp, ans)
	}
}

func getMaxNumLen(ans []int) int {
	maxNum := ans[0]
	for i := 0; i < len(ans); i++ {
		if maxNum < ans[i] {
			maxNum = ans[i]
		}
	}
	maxStr := strconv.Itoa(maxNum)
	return len(maxStr)
}

func setBucket(ans []int, num int) [][]int {
	tmp := make([][]int, 10000000)
	for j := 0; j < len(ans); j++ {
		bucketValue := ans[j] % num / (num / 10)
		tmp[bucketValue] = append(tmp[bucketValue], ans[j])
	}
	return tmp
}

func getArray(tmp [][]int, ans []int) {
	cnt := 0
	for i := 0; i < 10; i++ {
		for j := 0; j < len(tmp[i]); j++ {
			ans[cnt] = tmp[i][j]
			cnt++
		}
	}
	//ExportArray(ans)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章