排序算法
對十萬個隨機數進行排序
排序算法的穩定性和排序算法分類
排序算法的穩定性:能保證兩個相等的值,在排序前他們的相對位置不變,即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)
}