Golang-两种基于选择和插入的排序

希尔排序与堆排序

一、插入排序-希尔排序

希尔排序是基于插入排序的一种算法, 在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度为O( n3/2),空间复杂度为O(1),不需要大量的辅助空间,但它的稳定性是不稳定的。为什么会出现这个算法呢?是由于当考虑到所插入的数据是最小的时候,需要一直移位到头位置,显得效率很低,于是就有了分组插入的思想。
希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比O(n2)好一些。

以下由我画的图来分解理解一下希尔排序是怎么排序的:

根据上面的图片我们可以很清晰的写出对应的代码:

package main
import "fmt"
//插入排序——希尔排序
func main() {
	var arr = [...]int{3, 5, 2, 7, 8, 0, 1, 99}
	shellSort(&arr)
	fmt.Println(arr)
}
//交换式
func shellSort(arr *[8]int) {
	for gap := len(arr) / 2; gap > 0; gap /= 2 {
		for i := gap; i < len(arr); i++ {
			for j := i - gap; j >= 0; j -= gap {
				if arr[j] > arr[j+gap] {
					arr[j], arr[j+gap] = arr[j+gap], arr[j]
				}
			}
		}
	}
}

是不是很简单?

二、选择排序-堆排序

堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。

那什么是堆呢?
每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆
在这里插入图片描述

每个结点的值都小于于或等于其左右孩子结点的值,称为小顶堆
在这里插入图片描述
堆排序的思想:
*将待排序序列构造成一个大顶堆(小顶堆)
*此时,整个序列的最大值(最小值)就是堆顶的根节点。
*将其与末尾元素进行交换,此时末尾就为最大值(最小值)。
*然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值(次大值)。如此反复执行,便能得到一个有序序列了。

接下来就是堆排序的步骤分解:
在这里插入图片描述
再来看看代码怎么实现的吧!看不太理解图的也可以看看代码的注释!

package main
import "fmt"
func main() {
	var arr = [...]int{3, 5, 2, 7, 8, 0, 1, 99}
	heapSort(&arr)
	fmt.Println(arr)
}
//选择排序---堆排序
func heapSort(arr *[8]int) {
	//将一个无序的数组建成堆,从最后一个非叶子结点开始
	for i := len(arr)/2 - 1; i >= 0; i-- {
		adjustHeap(arr, i, len(arr))
	}
	//将堆顶元素与数组末尾交换,将最大元素放置数组末端
	//重新调整至堆结构,然后继续将堆顶元素和当前末尾元素交换以此往复。
	//重新调整堆结构的时候,数组长度是要减去已排好的长度。
	for i := len(arr) - 1; i > 0; i-- {
		arr[i], arr[0] = arr[0], arr[i]
		adjustHeap(arr, 0, i)//从根节点开始调整
	}
}
//将二叉树数组调整为堆
func adjustHeap(arr *[8]int, i, length int) {
	temp := arr[i]
	//i*2+1是非叶子结点的左子节点
	for k := i*2 + 1; k < length; k = k*2 + 1 {
	//找到比temp还大的子节点
		if k+1 < length && arr[k] < arr[k+1] { //判断左子节点是否大于右子节点
			k++ //若左小于右那么将当前k指向右子节点
		}
		if arr[k] > temp { //判断子节点是否大于当前结点
			arr[i] = arr[k] //是的话就把子节点赋给当前结点
			i = k           //将当前值作为比较点,但仍然是用temp比较,因为这个时候i=k temp在arr[k]位置
		} else {
			break
		}
	}
	arr[i] = temp
}

以上就是进化后的两种排序!记得每天都要学习喔~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值