後臺開發學習筆記(九、二叉堆)

終於把樹簡單學習完了,這裏只是簡單學習完了,以後樹的用處還有很多,以後在補補,這裏先往後走,二叉堆,這個我們在排序算法中堆排序裏已經用過了,不過這裏簡單描述一下二叉堆。

9.1 二叉堆簡介

9.1.1 簡介

二叉堆本質上是一種完全二叉樹,它分爲兩個類型。

  1. 最大堆:任何一個父節點的值,都大於或等於它左右孩子結點的值。
  2. 最小堆:任何一個父節點的值,都小於或等於它左右孩子結點的值。
    在這裏插入圖片描述
    圖片來自:https://blog.csdn.net/varyall/article/details/81099681

二叉堆的根結點叫做堆頂,最大堆的堆頂是這個堆中的最大值,最小堆的堆頂是這個堆中的最小值

9.1.2 二叉堆代碼結構

二叉堆的存儲方式不是鏈式結構,而是用順序存儲的,因爲這個二叉堆就是一個完全二叉樹,用數組存儲也是合理利用空間。

這裏以最小堆爲例介紹,優先隊列是最大堆,這樣兩個都可以介紹了。

我們看的時候還是要畫成二叉樹的風格,這樣有利於我們理解,
在這裏插入圖片描述
這個就是最小堆,是不是很想二叉樹,不過跟二叉樹性質不一樣,最小堆的父節點是最小值,排序二叉樹的父節點是中間值。

代碼中的存儲結構:
在這裏插入圖片描述
就是這樣的順序結構,這裏沒有指向左右孩子的指針,那怎麼找到左右孩子呢?
這個我們就要利用數組的下標了,
假設父節點的下標爲parent,左孩子的下標是2 * parent + 1 ,右孩子的下標爲 2 * parent + 2。
**假設孩子結點的下標爲child,那麼父節點的下標爲 (child - 1)/ 2. **
這個很重要,在代碼中就是移動的關鍵。

代碼:

typedef Elemtype int;

typedef struct binHeap
{
	int size;			//data數組的長度
	int len;			//有對少有限數據
	Elemtype *data;		//data數據
}_binHeap;

9.1.3 二叉堆的創建

二叉堆的創建比較簡單,跟創建一個棧差不多,都是申請數據,填充長度信息

/**
    * @brief  創建binHeap對象
    * @param  
    * @retval 
    */ 
    struct binHeap *binHeap_creat(int size)
    {
		struct binHeap *heap = (struct binHeap *)malloc(sizeof(struct binHeap));
		assert(heap);

		Elemtype *data = (Elemtype *)malloc(sizeof(Elemtype) *size);
		assert(data);

		heap->len = 0;
		heap->data = data;
		heap->size = size;
	
        return heap;
    }

/**
    * @brief  銷燬binHeap對象
    * @param  
    * @retval 
    */ 
    int binHeap_destroy(struct binHeap *heap)
    {
		assert(heap);

		if(heap->data)
			free(heap->data);

		if(heap)
			free(heap);
		
		return 0;
    }

9.2 二叉堆插入

9.2.1 插入介紹

又來到我們插入環節,這個二叉堆的插入也是比較簡單的,二叉堆的插入就兩個步驟:
第一,插入到最後一個元素,二叉堆前面的元素都已經符合了最大堆或最小堆的性質,所以新添加的要加入到最後一個元素裏。
第二,上浮,新加的一個元素不可能就一定會滿足最大堆或最小堆的性質,所以需要調整,這個調整就是上浮。

9.2.2 插入

二叉堆的插入比較簡單,從上面都已經看到二叉堆的存儲結構是數據,所以只要找到數據最後一個元素插入即可。

代碼:

/**
    * @brief  二叉堆插入
    * @param  
    * @retval 
    */ 
	int binHeap_insert(struct binHeap *heap, Elemtype data)
	{
		//判斷數據元素是否已經超出
		if(heap->size <= heap->len + 1)   //可以實現擴容
			return -1;

		heap->data[heap->len] = data;

		minHeap_upAdjust(heap);
	
		return 0;
	}

是不是看着很簡單,minHeap_upAdjust這個函數下節講,這纔是插入的重點。

9.2.3 上浮

插入比較簡單的話,那就是調整比較複雜了,像紅黑樹那樣,調整起來多難受,不過這個二叉堆調整起來也簡單,只要不斷的把最小結點往上提即可。

簡單的插入過程:
在這裏插入圖片描述
插入1,然後可以往上浮:
在這裏插入圖片描述
還不滿足,繼續上浮:
在這裏插入圖片描述
這樣就完成了一個上浮操作,結點多的時候,也是這個道理。

代碼:

/**
	* @brief  最小堆調整
	* @param  
	* @retval 
	*/ 
	static int minHeap_upAdjust(struct binHeap *heap)
    {
		//調整的時候,就是不斷的和父節點比較,然後判斷是否替換父節點

		int child = heap->len - 1; 
		int parent = (child - 1)/2;
		Elemtype temp = heap->data[heap->len-1];

		//開始循環比較
		while(child)
		{
			
			//跟第一個父節點比較
			if(temp < heap->data[parent]){
				//上浮
				heap->data[child] = heap->data[parent];
				child = parent;
				parent = (child - 1)/2;
			}
			
		}

		heap->data[child] = temp;
		return 0;
	}

9.3 二叉堆刪除

9.3.1 刪除介紹

刪除跟插入是反方向的,不過大體邏輯一樣,也是先刪除在調整,廢話就不多說了,直接下節,刪除。

9.3.2 刪除

二叉堆的刪除跟插入不一樣,插入是插入到最後一個元素,但是刪除是刪除第一個元素,爲什麼刪除第一個呢?因爲第一個元素是這個堆中的最大值或者最小值,我們用了二叉堆這個數據結構,就是必然對最大值或最小值感興趣,所以刪除的是第一個元素。

代碼:

/**
	* @brief  二叉堆刪除
	* @param  
	* @retval 
	*/ 
	int binHeap_delete(struct binHeap *heap)
	{
		//判斷數據元素是否已經超出
		if(heap->size <= 0)   //可以實現擴容
			return -1;

		int head = heap->data[0];

		heap->data[0] = heap->data[heap->len-1];
		heap->len--;

		minHeap_downAdjust(heap);
	
		return head;
	}

9.3.3 下沉

下沉步驟:
在這裏插入圖片描述
刪除1,然後最後一個元素4替換到1的位置:
在這裏插入圖片描述
然後開始下沉:
在這裏插入圖片描述
然後下沉完成,我畫的比較簡單,不過原理確實這樣。

代碼:

/**
	* @brief  最小堆下沉
	* @param  
	* @retval 
	*/ 
	static int minHeap_downAdjust(struct binHeap *heap)
	{
		//調整的時候,就是不斷的和孩子結點比較,然後獲取到那個孩子結點的值比父節點的小,替換父節點

		int parent = 0;
		int left_child = 2 * parent + 1;
		int right_child = 2 * parent + 2;
		int child = left_child;

		Elemtype temp = heap->data[parent];
		
		while(parent < heap->len)
		{
			//如果存在右孩子,並且右孩子小於左孩子,
			if(right_child < heap->len && heap->data[right_child] < heap->data[left_child]) {
				child = right_child;  //父節點要跟右孩子比較
			}

			//判斷父節點如果小於等於最小孩子結點,就不用移動
			if(temp <= heap->data[child])
				break;

			//這個需要下沉
			heap->data[parent] = heap->data[child];
			parent = child;
			left_child = parent * 2 + 1; 
			right_child = parent * 2 + 2; 
			child = left_child; 
		}

		heap->data[parent] = temp;
		return 0;
	}

9.4 構建二叉堆

構建二叉堆其實就是堆排序,想看詳細步驟可以看《二、排序算法下》中的堆排序,這裏也是就不描述了。(本來是要寫的,但是上面寫的代碼都是基於優先隊列的寫的,所以這裏就不寫了)

9.5 優先對列

隊列我們前面已經講過了,就是先進先出,入隊操作,元素加到隊尾,出隊操作,首元素出隊。

優先對壘有什麼特殊的呢?
優先隊列分爲兩種情況:
最大優先隊列,無論入隊順序如何,都是當前最大的元素優先出隊
最小優先隊列,無論入隊順序如何,都是當前最小的元素優先出隊

看到這兩種情況就想到我們的二叉堆,二叉堆會把最小值或最大值調整到第一個元素。
出隊的時候,獲取到第一個元素即可,然後再調整,就想到上面寫的刪除操作。
入隊操作:這個就更簡單,直接插入到隊尾,然後調整,這個跟上面的插入操作一樣。

代碼參考上面,這裏就不寫了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章