集中常见的排序方法Go语言版本实现

简单排序:插入排序、选择排序、
冒泡排序 分治排序:快速排序、归并排序
分配排序:桶排序、基数排序
树状排序:堆排序
其他:计数排序、希尔排序

稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 仍然在 b 的前面,则为稳定排序。
非稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 可能不在 b 的前面,则为非稳定排序。
原地排序:原地排序就是指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。
非原地排序:需要利用额外的数组来辅助排序。
时间复杂度:一个算法执行所消耗的时间。
空间复杂度:运行完一个算法所需的内存大小。

/**  insertSort   * 插入排序法     * @param arr     * @return     */
func insertSort(arr []int) {
	//	//判断数组是否为空或者长度是否大于2
	if len(arr) < 2 {
		return
	}
	//循环遍历数组
	for i := 1; i < len(arr); i++ {
		//定义变量保存要插入的值
		tem := arr[i]
		k := i - 1
		for k >= 0 && arr[k] > tem {
			arr[k+1] = arr[k]
			k--
		}
		//元素插入
		arr[k+1] = tem
	}
	return
}

// selectSort 选择排序 时间复杂度可能很高
func selectSort(arr []int) {
	n := len(arr)
	for i := 0; i < n-1; i++ {
		m := i
		for j := i + 1; j < n; j++ {
			if arr[m] > arr[j] {
				m = j
			}
		}
		//交换
		temp := arr[i]
		arr[i] = arr[m]
		arr[m] = temp
	}
}

// bubbleSort 冒泡排序算法
func bubbleSort(arr []int) {
	if len(arr) < 2 {
		return
	}
	flag := true
	//加一个标志位,记录上一次是否发生了交换,如果是,我们则进行下一轮,如果没有,说明已经冒泡好了
	for i := 1; i < len(arr) && flag; i++ {
		//控制次数,第几趟排序,只需要n-1趟,有交换时进行,只有flag=false就说明上一次一个元素都没有进行交换
		flag = false
		//假定未交换
		for j := 0; j < len(arr)-i; j++ {
			if arr[j] > arr[j+1] {
				temp := arr[j]
				arr[j] = arr[j+1]
				arr[j+1] = temp
				flag = true
			}
		}
	}
}

// quickSort 快速排序算法
func quickSort(arr []int, left, right int) []int {
	if left < right {
		//获取基点元素所处的位置
		mid := partition(arr, left, right)
		//进行分割
		arr = quickSort(arr, left, mid-1)
		arr = quickSort(arr, mid+1, right)
	}
	return arr
}
func partition(arr []int, left, right int) int {
	//选取基点元素
	pivot := arr[left]
	i := left + 1
	j := right
	for {
		// 向右找到第一个小于等于 pivot 的元素位置
		for i <= j && arr[i] <= pivot {
			i++
		}
		// 向左找到第一个大于等于 pivot 的元素位置
		for i <= j && arr[j] >= pivot {
			j--
		}
		if i >= j {
			break
		}
		//交换两个元素的位置,使得左边的元素不大于pivot,右边的不小于pivot
		temp := arr[i]
		arr[i] = arr[j]
		arr[j] = temp
	}
	arr[left] = arr[j]
	// 使中轴元素处于有序的位置
	arr[j] = pivot
	return j
}

// 堆排序
func heapSort(arr []int) {
	//1.构建大顶堆
	for i := len(arr)/2 - 1; i >= 0; i-- {
		//从第一个非叶子结点从下至上,从右至左调整结构
		sift(arr, i, len(arr))
	}
	//2.调整堆结构+交换堆顶元素与末尾元素
	for i := len(arr) - 1; i > 0; i-- {
		//现在的数组第一个就是根结点,最小值所在,进行交换,把它放到最右边
		temp := arr[i]
		arr[i] = arr[0]
		arr[0] = temp
		//重新建立堆
		sift(arr, 0, i)
		//重新对堆进行调整
	}
}

/**
 建立堆的方法
 私有方法,只允许被堆排序调用
 @param arr     要排序数组
 @param parent  当前的双亲节点
 @param len     数组长度
 */
func sift(arr []int, parent, len int) {
	value := arr[parent]
	//先取出当前元素i
	for child := 2*parent + 1; child < len; child = child*2 + 1 {
		//从parent结点的左子结点开始,也就是2*parent+1处开始
		if child+1 < len && (arr[child] < arr[child+1]) {
			//如果左子结点小于右子结点,child指向右子结点
			child++
			//右孩子如果比左孩子大,我们就将现在的孩子换到右孩子
		}
		//判断是否符合大顶堆的特性, 如果右孩子大于双亲,自然左孩子也大于双亲,符合
		//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
		if value < arr[child] {
			arr[parent] = arr[child]
			parent = child
		} else {
			//如果不是,说明已经符合我们的要求了。
			break
		}
	}
	arr[parent] = value
	//将value值放到最终的位置
}

附个二分查找算法

func Search(n int, f func(int) bool) int {
	// Define f(-1) == false and f(n) == true.
	// Invariant: f(i-1) == false, f(j) == true.
	i, j := 0, n
	for i < j {
		h := int(uint(i+j) >> 1) // avoid overflow when computing h
		// i ≤ h < j
		if !f(h) {
			i = h + 1 // preserves f(i-1) == false
		} else {
			j = h // preserves f(j) == true
		}
	}
	// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
	return i
}
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值