当前位置: 首页 > news >正文

有域名怎么建网站南宁怎么开自己的网站

有域名怎么建网站南宁,怎么开自己的网站,青岛鑫隆建设集团网站,简单电商网站模板下载一、优先级队列 ① 什么是优先级队列? 在此之前,我们已经学习过了"队列"的相关知识,我们知道"队列"是一种"先进先出"的数据结构,我们还学习过"栈",是"后进先出"的…

一、优先级队列

① 什么是优先级队列?

在此之前,我们已经学习过了"队列"的相关知识,我们知道"队列"是一种"先进先出"的数据结构,我们还学习过"栈"是"后进先出"的数据结构,这两种数据结构通常能够帮助我们在解题时存储一些数据,但是经过一段时间的练习,我们应该也能意识到这两种数据结构的缺点:"不够灵活"。

因为在有些情况下,我们要存储的数据并非是只存取队头或者队尾,有时我们还想使数据拥有一种排序的规律,使得我们能够随时取出和存入"按照这种规律下,优先级较高的数据",而想要实现这一点,即便是"栈"与"队列"两者的结合"双端队列",都是无法轻易办到的。

📚 比如:有时考试我们会按照学生的成绩进行分配考场,想在一个考场中提出或者放入一个学生,就要根据他的考试成绩来判断。

于是——优先级队列(PriorityQueue)出现了

二、优先级队列的模拟实现

优先级队列是一种能够按照指定的排序方式,自动将数据存到合理的位置的数据结构。它的底层实际上就是通过类似二叉树的结构来实现的~

优先级队列可以分为两种

📕 大根堆(这棵二叉树中,每棵树的根节点都比它左右子树的根节点大)

📕 小根堆(这棵二叉树中,每棵树的根节点都比它左右子树的根节点小)

(需要注意的是:根总是一棵完全二叉树)

📚 比如:此时我们有一组数据为{10,7,12,6,8,4},那么按照小根堆的形式存储它,就是:

这样的一颗二叉树,那么接下来我们一点点的去探究,优先级队列究竟是如何实现的:

① 基本框架

(java默认的优先级队列为小根堆,所以我们这里尝试模拟实现一个大根堆)

与之前一些数据结构的模拟实现较为类似,由于"堆"是一棵完全二叉树,所以这里我们的模拟实现就不再使用链表了。而是直接使用数组进行实现(通过层序遍历的顺序),所以我们需要最基本的一个整数数组elem,还需要一个记录有效数据个数的usedSize~

import java.util.*;public class MyHeap {public int[] elem;public int usedSize;public MyHeap() {}//对elem进行初始化public void init(int[] array) {}//创建一个优先级队列public void createHeap(int[] array) {}//向下调整private void shiftDown(int root,int len) {}//元素入队(不破坏优先级队列结构)public void push(int val) {}//向上调整private void shiftUp(int child) {}//判满public boolean isFull() {}//出队public void pollHeap() {}//判空public boolean isEmpty() {}//获取队顶元素public int peekHeap() {}
}

② 初始化elem

📚 思路提示

该方法用于我们先将数组存入elem中,以便我们后续的操作,我们只需要将数组中的元素存入elem,并且在初始化elem途中,适时的对elem进行扩容即可~

📖 代码示例

    //对elem进行初始化public void init(int[] array) {int len = array.length;for (int i = 0; i < len; i++) {if (isFull()) {elem = Arrays.copyOf(elem, elem.length * 2);}elem[i] = array[i];usedSize++;}}
    //判满public boolean isFull() {return usedSize == elem.length;}

③ 堆的向下调整

📚 思路提示

想要创建一个大根堆,就需要我们上面提到的大根堆性质"每棵树的根节点都比它左右子树的根节点大"

而想要使我们的elem中的元素也遵从这种规律,我们就要知道应该如何去对堆中的元素位置进行调整。其实还是比较简单的:

📚 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有结点从0开始编号,则对于序号为i的结点有以下性质:

📕 若孩子节点下标为 i ,那么父亲结点为 (i - 1) / 2 [i > 0]

📕 若父亲节点下标为 i ,那么左孩子节点为 2 * i + 1 [2i + 1 < n],右孩子节点为 2 * i + 2  [2i + 2 < n]

📕 首先,将需要调整的元素下标记作parent

📕 如果parent存在左孩子,则通过公式,算出parent的左孩子结点child

📕 如果有两个孩子结点,则将孩子结点标记为值最大的孩子

📕 判断孩子结点与父亲结点的大小,如果孩子更大,则交换孩子与父亲结点(大根堆)

📕 如果交换了结点,则将parent标记为child,再重新求child

图示

📖 代码示例

    //向下调整private void shiftDown(int parent,int len) {int child = parent * 2 + 1;while(child < len){//判断是否有右孩子,并且右孩子是否更大if(child + 1 < len && elem[child + 1] > elem[child]){child++;}if(elem[child] > elem[parent]){swap(elem,child,parent);parent = child;child = parent * 2 + 1;}else {break;}}}
    public void swap(int[] arr,int i,int j){int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}

④ 堆的创建

📚 思路提示

我们刚刚所实现的"向下调整",其实就是为了这一步我们成功的构建出一个"大根堆"而进行的铺垫

我们可以注意到,在上面的"向上调整"中,我们每一次进行交换,其实就是创建出了一个"这三个元素组成的局部大根堆",而想将整个数组都变成大根堆,我们就可以对数组中每一个有子节点的根进行向下调整~

📖 代码示例

    //创建一个优先级队列public void createHeap() {int len = elem.length;int parent = (elem.length - 1 - 1) / 2;for(int i = parent;i >= 0;i--){shiftDown(i,len);}}

这里或许大家会有一个疑问:为什么从最后一个根节点向上调整,而不是从第一个根节点向下调整?这是因为,两种看似一样的方法,其实时间复杂度相差并不小:

📕 如果从第一个根节点开始向下调整

对于根节点(位于第 1 层),它可能需要向下调整到叶子节点(第 log n 层),因此调整的时间复杂度是 O(log n)。

对于第 2 层的节点,它们可能需要向下调整到第 log n - 1 层,时间复杂度是 O(log n - 1)。

以此类推,直到叶子节点(不需要调整)。

这种方式的调整,时间复杂度为O(nlogn)

📕 如果从最后一个根节点向上调整

直接能够越过所有的叶子节点(最好的情况占结点总数一半 + 1)

对于剩余的结点,调整取决于它们的高度,并且越接近根节点,需要调整的高度越低。

这种方式的调整,时间复杂度接近O(n)

⑤ 堆的插入

📚 思路提示

顾名思义,就是在堆中插入一个元素,但是我们需要注意的是,不论是此刻的插入,亦或是之后我们需要进行的删除,都要保证操作后仍然为大根堆。所以在我们将新的元素插入到堆的末尾后,还要将该元素不断地向上进行调整,直到在某一刻符合大根堆的条件,停止调整。

📕 对堆进行判满,如果堆已满则进行扩容

📕 将新的元素插入堆的末尾,usedSize++

📕 对新元素进行向上调整:

📕 将元素下标标记为child,并且通过公式求出它的parent

📕 如果 parent >= 0 判断child和parent的值,如果child更大,两者进行交换否则调整结束

(因为在此之前,已经是标准的大根堆,所以不需要进行两个child的判断,只调整目标结点即可)

📕 如果进行了交换,则再将parent = child,然后重新求parent

图示

📖 代码示例

    //元素入队(不破坏优先级队列结构)public void push(int val) {if(isFull()){elem = Arrays.copyOf(elem, elem.length * 2);}elem[usedSize] = val;shiftUp(usedSize++);}
    //向上调整private void shiftUp(int child) {int parent = (child - 1) / 2;while(parent >= 0){if(elem[child] > elem[parent]){swap(elem,child,parent);child = parent;parent = (child - 1) / 2;}else {break;}}}

⑥ 堆的删除

(注意:堆的删除指的是删除堆顶元素)

📚 思路提示

想要删除一个堆顶元素,我们首先知道的是"usedSize"需要减一,那么我们由这点思考一下,如果不进行任何操作,首先usedSize--后,我们的堆中实际上消失的是哪个元素?没错,就是堆中的最后一个元素~,但是我们想删除的并不是该元素,而是我们的堆顶元素,简单呀~将这两个元素互换一下不就好了~最后再将新的堆顶元素进行向下调整即可~

📕 首先,判断该堆是否为空,若为空则直接退出该方法

📕 将堆顶元素与堆中最后一个元素进行交换

📕 然后将usedSize--

📕 最后将新的堆顶元素进行向下调整

图示

📖 代码示例

    //出队public void pollHeap() {if(isEmpty()){return;}swap(elem,0,--usedSize);shiftDown(0,usedSize);}
    //判空public boolean isEmpty() {return usedSize == 0;}
    //获取队顶元素public int peekHeap() {return elem[0];}

完整代码:

import java.util.*;public class MyHeap {public int[] elem;public int usedSize;public MyHeap(){elem = new int[10];}//创建一个大根堆public void creative(int[] arr){for(int i = 0;i < arr.length;i++){if(isFull()){elem = Arrays.copyOf(elem,elem.length * 2);}elem[i] = arr[i];usedSize++;}}public void doArr(){//最后一个叶子结点的父结点int start = (usedSize - 1 - 1) / 2;for(int i = start;i >= 0;i--){siftDown(i,usedSize);}}//将较大的子节点与父结点交换//向下调整public void siftDown(int parent,int end){//找到父结点的的左子结点int child = parent * 2 + 1;//保证该子结点未越界while(child < end){//查找左右子结点中的最大子结点//(包含了找出最大值后,对右子节点的判断)if(child + 1 < end && elem[child] < elem[child + 1]){child++;}//判断是否需要与父结点交换(判断大小)if(elem[child] > elem[parent]){int tmp = elem[child];elem[child] = elem[parent];elem[parent] = tmp;parent = child;child = parent * 2 + 1;}else {break;}}}//向堆中添加新元素public void offer(int val){if(isFull()){elem = Arrays.copyOf(elem,elem.length * 2);}elem[usedSize] = val;siftUp(usedSize);usedSize++;}//向上调整public void siftUp(int child){int parent = (child - 1) / 2;while(parent >= 0){if(elem[child] > elem[parent]){int tmp = elem[child];elem[child] = elem[parent];elem[parent] = tmp;child = parent;parent = (child - 1) / 2;}else {break;}}}//删除元素public int poll(){int oldValue = elem[0];elem[0] = elem[--usedSize];siftDown(0,usedSize);return oldValue;}//将堆排序成从小到大的顺序public void heapSort(){int end = usedSize - 1;while(end > 0){int tmp = elem[end];elem[end] = elem[0];elem[0] = tmp;siftDown(0,end);end--;}}public boolean isFull(){return usedSize >= elem.length;}
}

这篇文章我们对"优先级队列"进行了基本的认识,并且自己也尝试着模拟实现了一个大根堆,关于"优先级队列"的后续知识我将在后面的文章中为大家讲解,那么这篇文章到这里就结束啦,作者能力有限,如果有哪里说的不够清楚或者不够准确,还请各位在评论区多多指出,我也会虚心学习的,我们下次再见啦

http://www.zhongyajixie.com/news/56623.html

相关文章:

  • 上海平台网站制作公司哪家好友链外链app
  • 蛇口做网站佛山百度提升优化
  • 励志故事网站源码内江seo
  • 美团网网站建设 费用百度渠道开户
  • 怎么区分模板网站企业网站建设的流程
  • 有没有做头像的网站网址浏览大全
  • 重庆建立公司网站沈阳今日新闻头条
  • 公司建立网站的费用如何做帐站长工具seo排名
  • 南昌做网站哪家好站外推广渠道有哪些
  • 简单的网站开发的软件有哪些合肥seo网络优化公司
  • 中国工程建设焊接协会网站南京seo优化公司
  • 17网站一起做网店怎么样百度一下就知道手机版
  • 更改wordpress默认登录后台网站seo优化建议
  • 佛山免费自助建站模板销售平台
  • wordpress贴吧seo关键词优化指南
  • 2_试列出网站开发建设的步骤艾滋病阻断药
  • 宝安石岩网站建设高粱seo博客
  • 权威网站设计徐州seo排名收费
  • 网站备份数据库seo排名策略
  • 优秀的html5网站赣州seo培训
  • wordpress ssoseo资料站
  • 中国疫情最新情况今日新增银川seo
  • com域名多少钱360网站排名优化
  • 定制网站建设案例课堂提高网站排名的软件
  • 外贸一般在哪些网站汽车宣传软文
  • 建设网站的模板下载seo变现培训
  • 做cpa项目用什么网站信息流优化师简历模板
  • bc网站怎么做排名今日最新的新闻
  • 营销型网站的设计步骤首页优化排名
  • 杭州企业如何建网站企业推广平台排行榜