资讯 小学 初中 高中 语言 会计职称 学历提升 法考 计算机考试 医护考试 建工考试 教育百科
栏目分类:
子分类:
返回
空麓网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
空麓网 > 计算机考试 > 软件开发 > 后端开发 > Go语言

数据结构与算法 - 4 堆

Go语言 更新时间: 发布时间: 计算机考试归档 最新发布

数据结构与算法 - 4 堆

4. 堆 4.1 树与二叉树

树是一种数据结构,比如目录结构

树是一种可以递归定义的数据结构

树是由n个节点组成的集合:如果n=0,那这是一棵空树;如果n>0,那存在一个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树

二叉树:度不超过二的树

满二叉树:除了叶子节点,其它节点都有左子树和右子树

完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的节点都集中在该层最左边的若干位置的二叉树

二叉树的存储方式:链式存储和顺序存储

二叉树顺序存储方式下的编号:左:i -> 2i +1; 右:i ->2i +2

堆:是一种特殊的二叉树:

大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大

小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小

堆的性质:向下调整性质。当根节点的左右子树都是堆时,可以通过一次向下的调整来将其变换成一个堆

出数:每次拿最左边二叉树的叶子节点作为根节点,然后做向下调整

构造堆:看最后一个非叶子节点,每次调整小的

堆排序的过程:

1.建立堆,2.得到堆顶元素,为最大元素,3去掉堆顶,将堆最后一个碳元素放到堆顶,此时可以通过一次调整重新使堆有序,4.堆顶元素为第二大元素,5.重复步骤3,直到堆变空

代码实现:堆排序的时间复杂度是O(nlogn)

// Test example

//func main() {
//	//将下列随机数列顺序输出
//	s := []int{2, 8, 5, 6, 3, 9, 7, 1, 25, 23, 14, 0}
//	HeadSort(s)
//}

func HeadSort(s []int) {
	n := len(s)

	//将任意数列构造成堆

	for i := (n - 2) / 2; i >= 0; i-- {
		sift(s, i, n-1)
	}
	fmt.Println("排好的堆是:", s)

	//将堆从小到大排序
	for j := n - 1; j >= 0; j-- {
		s[0], s[j] = s[j], s[0]
		sift(s, 0, j-1)
	}
	fmt.Println("堆中元素按照顺序输出:", s)

}

//定义节点整理函数,将给定节点整理成堆

func sift(s []int, low int, high int) {

	//定义两个指针
	i := low     //第一个指针指向根节点
	j := 2*i + 1 //第二个指针指向根节点的左孩子

	tmp := s[low] //将根节点的数先取出存放

	for j <= high { //保证叶子节点不越界
		if j+1 <= high && s[j] < s[j+1] { //在右孩子有且大于左孩子的情况下,j越界会退出for循环,左孩子大时会执行下一个if语句
			j = j + 1 //第二个指针指向右孩子
		}
		if s[j] > tmp { //右孩子大于根节点
			s[i] = s[j] //将右孩子填充至根节点
			i = j       //将右孩子作为根节点,遍历下一层1
			j = 2*i + 1
			s[i] = tmp //将根节点填充到右孩子的位置,重新开始遍历
		} else { //右孩子小于根节点,不做改变
			s[i] = tmp
			break
		}
	}
	//fmt.Println(s) 测试代码
}
4.2 堆排序的应用 TOPK问题

现在有n个数,设计算法得到前k个大的数(k

解决思路:

  1. 排序后切片(O(nlogn));

  2. owB三人组(冒泡排序、选择排序、插入排序 O(n*n))

冒泡排序:需要k躺,O(kn)

插入排序:维护一个长度为k的列表,如果新来的数大于列表最后一个值,则插入

选择排序:选择100次

  1. 堆排序 O(nlogk)

    取列表的前k个元素建立一个小根堆,堆顶就是目前第k大的数

    依次向后遍历列表,对于列表中的元素,如果小于堆顶,则忽略该元素,如果大于堆顶,则将堆顶更换为该元素,并且对堆进行一次调整

    遍历列表所有元素后倒叙弹出堆顶

我们来看看代码

//Topk 问题算法

//Test example

//func main() {
//	//将下列随机数列顺序最大的七位
//	s := []int{2, 8, 5, 6, 3, 9, 7, 1, 25, 23, 14, 0}
//	Topk(s, 7)
//}

func Topk(s []int, k int) {
	heap := s[0:k]

	//建堆
	for i := (k - 2) / 2; i >= 0; i-- {
		sift(heap, i, k-1)
	}
	fmt.Println("新建的小根堆是:", heap)

	//遍历列表中所有剩余元素,如果大于堆顶,则纳入重新调整
	for j := k; j < len(s); j++ {
		if s[j] > heap[0] {
			heap[0] = s[j]
			Sift(heap, 0, k-1)
		}
	}
	fmt.Println("遍历后重新调整过的堆是:", heap)

	//挨个输出
	for h := k - 1; h >= 0; h-- {
		s[0], s[h] = s[h], s[0]
		Sift(s, 0, h-1)
	}
	fmt.Println("堆中元素按照顺序输出:", heap)

}

//定义节点整理函数,将给定节点整理成小根堆

func Sift(s []int, low int, high int) {

	//定义两个指针
	i := low     //第一个指针指向根节点
	j := 2*i + 1 //第二个指针指向根节点的左孩子

	tmp := s[low] //将根节点的数先取出存放

	for j <= high { //保证叶子节点不越界
		if j+1 <= high && s[j] > s[j+1] { //在右孩子有且大于左孩子的情况下,j越界会退出for循环,左孩子小时会执行下一个if语句
			j = j + 1 //第二个指针指向右孩子
		}
		if s[j] < tmp { //右孩子小于根节点
			s[i] = s[j] //将右孩子填充至根节点
			i = j       //将右孩子作为根节点,遍历下一层1
			j = 2*i + 1
			s[i] = tmp //将根节点填充到右孩子的位置,重新开始遍历
		} else { //右孩子大于根节点,不做改变
			s[i] = tmp
			break
		}
	}
	//fmt.Println(s) 测试代码
}
转载请注明:文章转载自 http://www.konglu.com/
本文地址:http://www.konglu.com/it/991404.html
免责声明:

我们致力于保护作者版权,注重分享,被刊用文章【数据结构与算法 - 4 堆】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理,本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2023 成都空麓科技有限公司

ICP备案号:蜀ICP备2023000828号-2