插入排序、二分插入排序、希尔排序算法分析及Go实现

今天闲的无聊,回忆一下算法:

  • 插入排序(直接插入排序)
  • 二分插入排序算法
  • 希尔排序算法

插入排序(直接插入排序)

基本思想

将一个记录插入到已排序好的有序表中,从而得到一个新且记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。(要点:设立哨兵,作为临时存储和判断数组边界之用)

在这里插入图片描述

代码
package main

import (
	"fmt"
	"math/rand"
)

func InsertSort(st []int) []int {
	if len(st) <= 1 {
		return st
	}
	for i := 1; i < len(st); i++ {
		back := st[i]
		j := i - 1
		for j >= 0 && back < st[j] {
			st[j+1] = st[j]
			j--
		}
		st[j+1] = back
	}
	return st
}
func main() {

	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	var list []int
	for i := 0; i < 100; i++ {
		list = append(list, r.Intn(100))
	}
	fmt.Println(InsertSort(list))
}

二分插入排序算法

基本思想

也是插入排序算法的一种,其基本思想是:引入二分查找的思想,在直接插入排序的基础上减少比较次数,从而更快的找到插入位置。
二分插入排序只是减少元素比较次数,并没有减少元素的移动次数,其相对直接插入排序性能并未有本质提升。
时间复杂度为T(n)=O(n^2),空间复杂度为S(n)=O(1)

在这里插入图片描述

代码
package main

import (
	"fmt"
	"math/rand"
)

func EInsertSort(st []int, start, end, cur int) int {
	//对比当前位置与需要排序的元素大小,返回较大值的位置
	if start >= end {
		if st[start] < st[cur] {
			return cur
		}
		return start
	}
	mid := (start + end) / 2

	//二分查找递归
	if st[mid] > st[cur] {
		return EInsertSort(st, start, mid, cur)
	} else {
		return EInsertSort(st, mid+1, end, cur)
	}

}

func main() {

	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	list := make([]int, 0)
	for i := 0; i < 100; i++ {
		list = append(list, r.Intn(100))
	}
	for i := 1; i < len(list); i++ {
		p := EInsertSort(list, 0, i-1, i)
		if p != i { //不等 需要插入
			temp := list[i]
			for j := i; j > p; j-- {
				list[j], list[j-1] = list[j-1], list[j]
			}
			list[p] = temp
		}
	}
	fmt.Println(list)

}

希尔排序算法

基本思想

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序 待整个序列中的记录“基本有序”时 再对全体记录进行依次直接插入排序

在这里插入图片描述

  • 实现简单处理增量序列 d = {n/2 ,n/4, n/8 …1}, n为要排序数的个数
  • 先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列
  • 每组中记录的下标相差d,对每组中元素进行直接插入排序
  • 再用一个较小的增量(d/2)对它进行分组
  • 在每组中再进行直接插入排序
  • 继续不断缩小增量直至为1,最后使用直接插入排序完成排序
代码
package main

import (
	"fmt"
	"math/rand"
)

/**
希尔排序:把切片分成n个batch,对每个batch进行插入排序;然后减小batch,再对每个batch进行插入排序;直到bathc等于1
*/
func shellSort(st []int, batchSize int) {
	if batchSize < 1 {
		return
	}
	// i : 每个batch中的元素所在batch的index, 介于[0, batchSize)
	for i := 0; i < batchSize; i++ {
		// 用到了插入排序
		for j := 1; batchSize*j+i < len(st); j++ { // j: 用来获取每个batch所在的第i个元素,拥有多少个batch
			for n := j; n > 0; n-- {
				pre := batchSize*(n-1) + i
				next := batchSize*n + i
				if st[next] < st[pre] {
					st[next], st[pre] = st[pre], st[next]
				}
			}

		}
	}
	shellSort(st, batchSize/2)
}

func main() {

	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	list := make([]int, 0)
	for i := 0; i < 100; i++ {
		list = append(list, r.Intn(100))
	}
	shellSort(list, len(list)/2)
	fmt.Println(list)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值