排序算法的GO语言实现

排序

冒泡排序

func BubbleSort(arr []int,arrLength int){
	for i:=0; i<arrLength; i++{
		flag := false
		//每一轮操作完,有i个元素已经是有序的,同时最后一个元素没有比较对象,不用比
		for j:=0;j<arrLength-i-1;j++{
			if arr[j] > arr[j+1]{
				arr[j],arr[j+1] = arr[j+1],arr[j]
				flag = true
			}
		}
		if !flag{
			break
		}
	}
}

插入排序

把数字插入到合适的位置

package algo

import "testing"

/**
第一个数字是有序的,从后面的数字取一个出来,放在有序范围内
 */
func insertionSort(arr []int,arrLength int){
	if arrLength <= 1 {
		return
	}
	for i:=1; i<arrLength; i++ {
		//从没有排序的区域取第一个
		value := arr[i]
		//从后往前,跟有序区域每一个数字比较
		j := i-1 //i-1是有序区域最后一个数字
		for ;j>=0;j--{
			//如果值比某个数字小,则该数字需要往后挪动一个位置
			if(arr[j] > value){
				arr[j+1] = arr[j]
			}else{
				//有序区域已经没有比该数字更大,退出
				break
			}
		}
		//把数字放在挪动出来的空位,j+1是为了补偿j--
		arr[j+1] = value
	}
}

选择排序

每次选择后面最小的数字放到有序区

//在无序区选择一个最小的数字放在有序区后面
func selectSort(arr []int,arrLength int){
	for i:=0; i<arrLength; i++{
		minIndex := i //先记录当前元素作为最小元素的索引
		//在无序区(i+1),从前往后找最小的索引
		for j:=i+1;j<arrLength;j++{
			if arr[j] < arr[minIndex] {
				minIndex = j
			}
		}
		//用最小元素替换有序区末尾元素,此时该区域(0~i)才是真正有序
		arr[minIndex],arr[i] = arr[i],arr[minIndex]
	}
}

快排

选择一个数字作为基准值,小的放左边,基准值放中间,大的放右边。不断重复这个过程

/**
选择一个数字作为基准值,小的放左边,大的放右边
 */
func QuickSort(arr []int){
	QuickSortInner(arr,0,len(arr)-1)
}

func QuickSortInner(arr []int,left int,right int){
	//递归结束条件,左右两边的索引重合,表示已经所有条件
	if(left >= right){
		return
	}
	q := partition(arr,left,right) //分区,并返回两个区中间数的索引
	partition(arr,left,q-1) //对小数区[left,q-1]分区
	partition(arr,right,q+1)//对大数区分区
}

func partition(arr []int,left int,right int) int{
	//选取最后一个值作为基准值
	pivot := arr[right]
	//有序区开始
	j := left
	//从左到右遍历,如果某个数字比基数小,该数字加入(交换) 已小数字区间[left,j-1]尾部,区间扩充
	//否则加入大数字区间,区间位置不变
	//(小->大)
	for i:=left;i<right;i++{
		if arr[i] < pivot {
			arr[i],arr[j] = arr[j],arr[i]
			j++
		}
	}
	//基数需要跟大数字区间第一个数字交换(因为比他大的都放在第一个数字后了)
	arr[j],arr[right] = arr[right],arr[j]
	return j
}

归并排序

把数组不断拆分成两半,直到成为一个单独的元素,然后传入数组的起点,中间点,终点,以中间点为边界合并两个有序的数组

func mergerSort(arr []int,start int,end int){
	//start >= end 表示整个数组已经拆分成一个个元素
	if start >= end {
		return
	}
	//把数组分成两半,分别对两半进行拆分
	middle := start + (end - start) / 2
	mergerSort(arr,start,middle)
	mergerSort(arr,middle+1,end)
	//拆分完后对两半进行合并操作
	merge(arr,start,middle,end)
}

//对两个有序数组进行合并操作,i是起点到中间点,j是中间点+1到终点
func merge(arr []int,start int, middle int, end int){
	//分别设置三个变量,两个作为有序数组的偏移量,k作为新数组的偏移量
	i := start
	j := middle+1
	k := 0
	//申请一个两个数组合并后大小的空间
	tmpArr := make([]int,end-start+1)
	//循环结束的条件是 其中一个数组已经遍历完
	//遍历的过程中新数组递加
	for ;i<=middle && j<=end; k++ {
		//把值更大的元素放入新数组,并且用该数组下一个元素对比
		if arr[j] > arr[i]{
			tmpArr[k] = arr[j]
			j++
		}else{
			tmpArr[k] = arr[i]
			i++
		}
	}

	//把i数组未循环完的元素放入临时变量
	for ;i<=middle;i++{
		tmpArr[k] = arr[i]
		k++
	}

	//把j数组未循环完的元素放入临时变量
	for ;j<=end;j++{
		tmpArr[k] = arr[j]
		k++
	}

	//把新数组的元素放回原数组,原数组需要从起点start偏移
	for i=0; i< len(tmpArr); i++{
		arr[start+i] = tmpArr[i]
	}
}

二分法

等值查找

场景:有序数据
注意点:

  • 循环退出条件是 low <= high
  • low和high的更新,low=mid+1,high=mid-1。注意这里的 +1 和 -1,如果直接写成 low=mid 或者 high=mid,就可能会发生死循环。
func bsearch(arr []int,value int) int{
	length := len(arr)
	high := length - 1
	low := 0
	for high >= low {
		mid := low + (high - low)/2
		if value == arr[mid] {
			return mid
		}else if(value > arr[mid]){
			low = mid + 1
		}else{
			high = mid - 1
		}
	}
	return -1
}

查找第一个大于等于value的元素

  • 如果 a[mid]小于要查找的值 value,那要查找的值肯定在[mid+1, high]之间,所以,我们更新 low=mid+1。
  • 对于 a[mid]大于等于给定值 value 的情况,我们要先看下这个 a[mid]是不是我们要找的第一个值大于等于给定值的元素。如果 a[mid]前面已经没有元素,或者前面一个元素小于要查找的值 value,那 a[mid]就是我们要找的元素。
  • 如果 a[mid-1]也大于等于要查找的值 value,那说明要查找的元素在[low, mid-1]之间,所以,我们将 high 更新为 mid-1。
func bsearch(arr []int,value int) int{
	length := len(arr)
	high := length - 1
	low := 0
	for low <= high {
		mid := low + (high - low)/2
                 //找到了一个大于等于value的元素
		if  arr[mid] >= value {
			//看看它前面有没有元素
                        //看看前一个元素是不是小于value
                        //都符合表示找到了
			if mid == 0 || arr[mid - 1] < value {
				return mid
			}else{
				//否则从mid前面找比value大的元素
				high = mid - 1
			}
		}else{
			//从后面找
			low = mid + 1
		}
	}
	return -1
}
posted @ 2020-04-26 22:04  defmain  阅读(183)  评论(0编辑  收藏  举报