网站可以用cdr做吗,做网站的工作室,明月浩空WordPress,网络营销的主要特点及举例文本目录#xff1a;
❄️一、优先级队列#xff1a; ➷ 1、概念#xff1a;
❄️二、优先级队列的模拟实现#xff1a; ➷ 1、堆的概念#xff1a; ➷ 2、堆的性质#xff1a; ➷ 3、堆的创建#xff1a; ▶ 向下调整#xff1a; ➷ 4、堆的插入和删除#xff1a; …文本目录
❄️一、优先级队列 ➷ 1、概念
❄️二、优先级队列的模拟实现 ➷ 1、堆的概念 ➷ 2、堆的性质 ➷ 3、堆的创建 ▶ 向下调整 ➷ 4、堆的插入和删除 ▶ 堆的插入 ☞ 思路 ☞ 代码 ▶ 堆的删除 ☞ 思路 ☞ 代码 ➷ 5、堆的判空和判满 ➷ 6、堆的对顶数据 ➷ 7、堆的总代码
❄️总结 ❄️一、优先级队列 ➷ 1、概念 我们在前面是介绍过队列的队列是一种先进先出的数据结构但是在有些情况下呢我们操作的数据有优先级这时候在我们出队列的时候呢可能需要先出优先级高的先出队列那么在这种情况下呢我们的队列就是有些不合适了比如呢我们在 玩游戏的时候呢来个电话是不是手机先处理电话之后再处理游戏去。 在这种情况下数据结构提供了两种最基本的操作一个事返回优先级最高的对象另一个是添加新的对象。这种操作呢就是 优先级队列——Priority Queue ❄️二、优先级队列的模拟实现 在 JDK1.8 中呢我们的 Priority Queue 的底层使用了堆的数据结构而对于 堆呢就是在 完全二叉树 的基础上进行一些调整的。 ➷ 1、堆的概念 如果有一个关键码的集合 K {K0K1K2.......Kn - 1}把它的所有数据都按照 完全二叉树的顺序存储方式存储 在一个一维数组中并且满足 Ki K2i 1 且 Ki K2i 2 (Ki K2i 1 且 Ki K2i 2) i 0,1,2,3,4,5....... 则称为 小堆(大堆)。 在这里我们 将根节点最大的堆称为 最大堆 或者 大根堆 将根节点最小的堆称为 最小堆 或者 小根堆 ➷ 2、堆的性质
• 堆中某个节点的值总是 不大于 或者 不小于 其父节点的值。
• 堆是一颗完全二叉树。
我们来看看 大根堆 和 小根堆 的逻辑结构和存储结构 我们的存储方式是采用 层序存储 的 规则来进行存储到数组中。这样就非常的高效了。 我们要注意如果不是 完全二叉树 的情况下呢我们的不能使用 层序遍历的存储规则这样会浪费空间所以如果不是完全二叉树不能这样做。 ➷ 3、堆的创建 我们在创建堆之前呢我们先来做一些准备工作我们要注意我们的堆的底层使用的是数组进行实现的。 我们将这些数据变成 大根堆 或者 小根堆 但是呢我们要如何才能创建 大根堆 或者 小根堆 呢
在创建 大根堆 或者 小根堆 之前呢我们先把这个数组的值呢变成 完全二叉树 来看看 我们红色的字体就是我们的数组的下标。这个就是我们这组数据的 完全二叉树 的逻辑结构。 那么我们要如何创建堆呢这里呢我们要了解到一个知识点——向下调整。 ▶ 向下调整 我们这里是 从最后一颗子树进行调整找到最后一颗子树的根节点再比较这个根节点的左右节点谁大我们把根节点和这个最大值进行调整这样循环调整每一颗子树。这样就可以调整成大根堆。
这里呢我们直接看图来理解这个问题
这就是我们的大根堆的调整方法从 完全二叉树 调整。
这里我们需要一些必须要求的东西
1、首先要找到最后一颗子树的位置也就是最后一颗子树的根节点。 这里我们使用一个公式数组的长度 - 1 - 1/ 2 就是我们的最后一颗子树的根节点。我们使用 parent 标记这个节点。
2、我们如何找到我们的下一颗子树的根节点位置 这个就比较简单了我们直接 parent-- 就可以了。直至我们的 parent 下标 0 即可比如
3、我们要知道我们的子树的 左子树 为什么是左子树呢因为是由 完全二叉树 调整而来如果 没有左子树就没有右子树所以只需要找到左子树即可。 那么怎样去找呢这里也有公式child parent * 2 1 就是我们左子树。但是这个呢我们还要找其左右子树最大的值不是直接对child进行交换的。并且要注意我们的 child 要 小于 有效的数组长度。 4、我们怎样知道我们的调整结束了 这里我们不能调整一次就结束这里的结束条件就是当我们的 左子树这个节点的下标比有效数组长度长的时候就是结束的时候了。 每次我们要对 child 和 parent 进行调整。parent child child parent * 2 1 我们来演示一变看看如何进行的
这就是我们的 向下调整 成 大根堆 的操作。来看看这个 向下调整 的代码
/**** param parent 每颗子树调整时候的起始位置* param usedSize 用来判断 每颗子树什么时候结束的*/private void shiftDown(int parent,int usedSize) {int child parent * 2 1;//parent根节点的左子树的节点while (child usedSize) {//判断有没有右子树如果有就把 child 设置为最大的值的下标if (child 1 usedSize elem[child 1] elem[child]) {//右子树比左子树大把 child 1就是右子树child 1;}if (elem[parent] elem[child]) {//进行交换swap(elem,child,parent);//调整完把 parent 和 child 进行调整位置parent child;child parent * 2 1;}else {//这是 parent下标的值大于child跳出break;}}}private void swap(int[] elem,int i,int j) {int tmp elem[i];elem[i] elem[j];elem[j] tmp;} 这个呢就是我们的 向下调整 的 创建大根堆对于我们的要是 创建 小根堆 的话就是把其小的数值进行调整就可以了就是反过来进行调整。 我们这个时候来看看对于堆的创建了解到 向下调整 之后呢就是非常的容易了我们呢就是把每一个 parent 进行 向下调整这里就用到循环遍历就可以了。 我们来看代码
//堆的创建public void createHeap() {for (int parent (this.usedSize - 1 - 1) / 2; parent 0 ; parent--) {shiftDown(parent,this.usedSize);}}
Ok啊这样我们的 大根堆的创建 就创建完成了。 ➷ 4、堆的插入和删除 ▶ 堆的插入 ☞ 思路 对于我们的堆的插入的操做呢我们的插入一定是在最后一个位置插入的这个位置我们一定是知道的就是我们的 usedSize 这个下标的位置插入数据。我们就可以根据这个位置求出其插入的值的根节点的位置。 我们来看图来理解 这个 90 就是我们新插入的值我们再对其进行 向上调整我们是知道插入值的下标就可以计算到根节点的下标就可以进行 向上调整了 。
再对其进行向上调整就可以了。 这里我们也要注意当我们的数组使用满了后我们就需要扩容了。
这个就是插入的操作了。我们来看看代码是如何编写的 ☞ 代码
//堆的插入public void offer(int val) {if (usedSize elem.length) {//满了。2倍扩容this.elem Arrays.copyOf(this.elem, 2 * this.elem.length);}//插入操作this.elem[usedSize] val;//这个时候 usedSize 位置就是我们的子树的坐标位置shiftUp(usedSize);this.usedSize;}private void shiftUp(int child) {int parent (child - 1) / 2;while (parent 0) {//进行向上调整if (this.elem[parent] this.elem[child]) {//交换swap(elem,child,parent);//parent 和 child 调整位置child parent;parent (child - 1) / 2;}else {break;}}}
OK这个呢就是我们的插入操作的代码了之后我们来看看删除操作是如何做到的。 ▶ 堆的删除 ☞ 思路 这个删除操作还是很简单的我们需要删除优先级高的数据所以我们删除的就是 0 下标的值
我们呢有三个步骤
1、把堆的 0 下标的数据 和 usedSize - 1 这个下标的数据进行交换就是第一个数据和最后一个 数据进行交换。
2、我们把有效数组长度减一。
3、我们就是 0 这个下标不是大根堆的结构所以我们对 0 这个下标进行 向下调整 操作。
这个呢就是我们删除的思路了我们接下来看看其代码 ☞ 代码
//堆的删除操作public int poll() {//删除优先级最高的就是0下标的值有三个步骤//1、把堆的第一个数据和最后一个数据进行交换//2、把有效数据长度进行减1//3、把 0 下标的值进行向下调整if (usedSize 0) {//堆为空结束return -1;}int val elem[0];//1、swap(elem,0,usedSize - 1);//2、usedSize--;//3、shiftDown(0,usedSize);return val;} ➷ 5、堆的判空和判满
这两个操作就非常的简单了我们直接来看代码 //判空public boolean isEmpty() {return usedSize 0;}//判满public boolean isFull() {return usedSize this.elem.length;} ➷ 6、堆的对顶数据
这个同样非常的简单我们直接返回下标为 0 的值就可以了。 //返回堆顶的数据public int peek() {if (isEmpty()) {return -1;}return this.elem[0];}
这样呢我们所有的基本操作就都完成了我们来看一下总代码 ➷ 7、堆的总代码
import java.util.Arrays;public class TestHeap {public int[] elem;public int usedSize;public TestHeap() {//初始话this.elem new int[10];}public void initElem(int[] array) {//把elem里的值设置为我们输入的值for (int i 0; i array.length; i) {elem[i] array[i];}}/*** 建堆的时间复杂度为O(N)。* 大根堆* param parent 每颗子树调整时候的起始位置* param usedSize 用来判断 每颗子树什么时候结束的*/private void shiftDown(int parent,int usedSize) {int child parent * 2 1;//parent根节点的左子树的节点while (child usedSize) {//判断有没有右子树如果有就把 child 设置为最大的值的下标if (child 1 usedSize elem[child 1] elem[child]) {//右子树比左子树大把 child 1就是右子树child 1;}if (elem[parent] elem[child]) {//进行交换swap(elem,child,parent);//调整完把 parent 和 child 进行调整位置parent child;child parent * 2 1;}else {//这是 parent下标的值大于child跳出break;}}}private void swap(int[] elem,int i,int j) {int tmp elem[i];elem[i] elem[j];elem[j] tmp;}//大根堆的创建public void createHeap() {for (int parent (this.usedSize - 1 - 1) / 2; parent 0 ; parent--) {shiftDown(parent,this.usedSize);}}//堆的插入public void offer(int val) {if (isFull()) {//满了。2倍扩容this.elem Arrays.copyOf(this.elem, 2 * this.elem.length);}//插入操作this.elem[usedSize] val;//这个时候 usedSize 位置就是我们的子树的坐标位置shiftUp(usedSize);this.usedSize;}private void shiftUp(int child) {int parent (child - 1) / 2;while (parent 0) {//进行向上调整if (this.elem[parent] this.elem[child]) {//交换swap(elem,child,parent);//parent 和 child 调整位置child parent;parent (child - 1) / 2;}else {break;}}}//堆的删除操作public int poll() {//删除优先级最高的就是0下标的值有三个步骤//1、把堆的第一个数据和最后一个数据进行交换//2、把有效数据长度进行减1//3、把 0 下标的值进行向下调整if (isEmpty()) {//堆为空结束return -1;}int val elem[0];//1、swap(elem,0,usedSize - 1);//2、usedSize--;//3、shiftDown(0,usedSize);return val;}//返回堆顶的数据public int peek() {if (isEmpty()) {return -1;}return this.elem[0];}//判空public boolean isEmpty() {return usedSize 0;}//判满public boolean isFull() {return usedSize this.elem.length;}
}❄️总结 OK这篇博客呢就到这里就结束了这篇博客我们介绍的是 优先级队列 的底层操作代码下一篇博客我们来看看 Java 自带的 优先级队列吧~~并且还有一些关于我们的优先级队列的习题敬请期待吧拜拜·~~~