日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

發布時間:2023/12/15 综合教程 45 生活家
生活随笔 收集整理的這篇文章主要介紹了 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

說到堆的相關知識,之前我在隊列中也說過一些,而且優先隊列就是使用的堆得思想,今天只是想主要說一下堆得上溢和下溢操作原理,也就是堆實現插入和刪除的原理。

一、堆的基礎知識

1、堆的定義

堆是一種類似于樹的結構的數據結構,堆有孩子節點,所有子節點均小于大于或者小于根節點。

2、堆的分類

最大堆:子節點值均小于根節點的值,這樣的堆叫做最大堆;

最小堆:子節點值均大于根節點的值,這樣的堆叫做最小堆。

3、堆的圖示

二、堆的上濾下濾(最小堆)

首先說一下堆的上溢和下溢的作用,堆的上溢操作主要是用來實現插入操作,堆的下溢操做主要是用來實現刪除操作。

1、上濾

說道上濾操作,我覺得結合堆的插入操作比較好理解。插入操作可以分為以下幾種方式:

(1)將新的節點插入最后的位置,記錄當前位置為n

(2)取插入新節點的父節點(即位置為n/2)比較值與當前新節點的值的大小,若比插入的值小,則將父節點值賦值到位置為n節點處。若比插入的值大,則將要插入的節點值,賦值給n位置的節點上,然后結束上濾。

(3)取n/2位置的父節點,也就是(n/2)/2位置節點與插入的值比較大小,若比插入的值小,則將父節點值賦值到位置為n/2節點處。若比插入的值大,則將要插入的節點值,賦值給n/2位置的節點上,然后結束上濾。

(4)取(n/2)/2位置的父節點,也就是((n/2)/2)/2位置節點與插入的值比較大小,若比插入的值小,則將父節點值賦值到位置為(n/2)/2節點處。若比插入的值大,則將要插入的節點值,賦值給(n/2)/2位置的節點上,然后結束上濾。

.....一直重復上濾過程,也就父節點的值比插入的值小。

(5)直到最后根節點,將插入的節點值賦值給根節點,然后結束上濾。

例如:下圖

插入值為2的節點,操作入下:

2、下濾

說到下濾我覺得結合堆的刪除操作一起來講比較好理解。首先我們將刪除的節點分類,無非兩種一個是非葉子結點,也就是某一個子樹的根,另一個為葉子結點。對于刪除的是葉子結點直接刪除,如果不是葉子結點則需要進行下濾操作。

刪除操作分為以下幾步:

(1)刪除的節點是否是葉子元素,是葉子元素直接刪除,刪除的不是葉子節點,則需要進行下濾操作。

(2)下濾操作的具體:1)先找到要刪除元素的位置,并記錄該元素的位置n

2)獲取并刪除該堆的最后一個元素,思想是前面的一個元素刪除了,最后的元素必定會緊湊到前面的某一位置上,先將這個值暫且填充到刪除的位置上,然 后調整位置

3)獲取n位置的孩子節點中最小的值,記錄該值的位置m,并且將該值與現在該位置的值比較大小,如果m位置的值比n位置值小的話,將m位置的值賦值 到n位置處,將n位置的值賦值 到m位置處;如果m位置的值比n位置值大的話,直接結束下溢過程。

4)獲取m位置的孩子節點中最小的值,記錄該值的位置k,并且將該值與現在該位置的值比較大小,如果k位置的值比m位置值小的話,將k位置的值賦值 到m位置處,將m位置的值賦值 到k位置處;如果k位置的值比m位置值大的話,直接結束下溢過程。

......一直重復上濾過程,也就孩子節點最小值比插入的值小,結束下溢過程。

5)直到最后葉節點,將插入的節點值賦值給葉節點,然后結束下濾。

例如:

刪除值為2的節點

三、堆的刪除(最小值刪除)和插入操作代碼(實質就是優先隊列的相關操作)

以最小堆為例

代碼示例:(Java)

 1 public class PriorityQueue1 {
 2     private final int DEFUALTSIZE=4;//默認的堆大小+1,即2的平方
 3     private int []queue1;//默認底層的數組存儲實現
 4     private int nowQueueSize=0;//記錄當前堆得元素的個數,隊列的元素個數
 5     //對優先隊列進行相關的初始化,申請一些空間
 6     public PriorityQueue1(){
 7         queue1=new int[DEFUALTSIZE];
 8     }
 9     //給優先隊列進行拓展空間存儲大小
10     public void enlargeArray(int newSize){
11         System.out.println("優先隊列進行拓展一次空間");
12          int []mark=queue1;
13          queue1=new int [newSize];
14          for(int i=0;i<mark.length;i++){
15              queue1[i]=mark[i];
16          }
17     }
18     public void push(int m){
19         //如果存儲空間不夠,申請新的空間
20         if(nowQueueSize==queue1.length-1){
21             enlargeArray(queue1.length*2);//拓展的大小是拓展了堆(樹)得下一層
22         }
23         //上溢操作
24         int markLocation=++nowQueueSize;
25         for(queue1[0]=m;queue1[markLocation/2]>m;markLocation/=2){
26             queue1[markLocation]=queue1[markLocation/2];
27         }
28         queue1[markLocation]=m;
29         //測試入隊列后的數組元素分布
30         for(int i=1;i<=nowQueueSize;i++){
31             System.out.print(queue1[i]+" ");
32         }
33         System.out.println();
34         
35     }
36     public int pop() throws Exception{
37         if(nowQueueSize==0){
38             throw new Exception("優先隊列已空,不能進行出隊列操作!");
39         }
40         //優先隊列的下溢操作
41         int mark=queue1[1];
42         for(int i=1;i<nowQueueSize;){
43             int markMin;
44             int markI;
45             if(2*i>nowQueueSize-1){
46                 queue1[i]=queue1[nowQueueSize];
47                 break;
48             }else if(2*i+1<=nowQueueSize-1){
49                 markMin=queue1[2*i]>queue1[2*i+1]?queue1[2*i+1]:queue1[2*i];
50                 markI=queue1[2*i]>queue1[2*i+1]?(2*i+1):(2*i);
51                 if(queue1[nowQueueSize]<markMin){
52                     queue1[i]=queue1[nowQueueSize];
53                     break;
54                 }else{
55                     queue1[i]=markMin;
56                     i=markI;                
57                 }
58             }else{
59                 markMin=queue1[2*i];
60                 markI=2*i;
61                 if(queue1[nowQueueSize]<markMin){
62                     queue1[i]=queue1[nowQueueSize];
63                     break;
64                 }else{
65                     queue1[i]=markMin;
66                     i=markI;
67                 }
68             }            
69         }    
70         nowQueueSize--;
71         return mark;
72     }
73     public static void main(String[] args) throws Exception {
74         PriorityQueue1 queueTest=new PriorityQueue1();
75         queueTest.push(2);
76         queueTest.push(4);
77         queueTest.push(3);
78         queueTest.push(1);
79         queueTest.push(6);
80         queueTest.push(5);
81         for(int i=1;i<=6;i++){
82             System.out.print(queueTest.pop()+" ");
83         }
84         System.out.println();
85         System.out.println(queueTest.pop());
86 
87     }
88 
89 }

運行結果:

4 
4 3 
優先隊列進行拓展一次空間
2 3 4 
2 3 4 6 
2 3 4 6 5 
2 3 4 5 6 
Exception in thread "main" java.lang.Exception: 優先隊列已空,不能進行出隊列操作!
    at Queue.PriorityQueue1.pop(PriorityQueue1.java:40)
    at Queue.PriorityQueue1.main(PriorityQueue1.java:87)

四、總結

其實堆也只是一種思想,思想上和數的結構很像,但是實現上我們可以有數組和鏈表實現,主要是了解這種思想。

關于的堆的合并操作,我找時間再補充吧!其實簡單。

總結

以上是生活随笔為你收集整理的的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。