1. 程式人生 > >搜尋樹和連結串列實現的堆

搜尋樹和連結串列實現的堆

目的:
1、建立最大堆類。最大堆的儲存結構使用連結串列。
2、提供操作:堆的插入、堆的刪除。堆的初始化。Huffman 樹的構造。二叉搜尋樹的構造。
3、接收鍵盤錄入的一系列整數,輸出其對應的最大堆、Huffman 編碼以及二叉搜尋樹。
4、堆排序。

堆是完全二叉樹,通常是用陣列實現的。但是在這裡題目有要求,所以我們要思考連結串列如何保持完全二叉樹的結構。
換句話說我們就是要找到完全二叉樹最後一個元素的位置,這樣我們就可以在插入和刪除操作時保證堆依然是完全二叉樹。
因為二叉樹本身就是遞迴定義的結構,完全二叉樹的子樹也是完全二叉樹,所以可以用一種遞迴方式,確定最後一個元素在左子樹還是右子樹中,直到不存在子樹為止。這種計算過程需要知道堆有幾個元素,所以可以給堆一個size屬性記錄元素個數。計算方法如下:

HeapNode<T> *p = root,//指向當前節點的指標
            *pp = 0;//指向當前節點的父節點的指標
int tsize = size; //將元素數儲存到一個臨時變數中
size--;
int height = 2; //下一層的元素個數
while (tsize >= height * 2) {
    height *= 2;
}
while (height > 1) {//一直進行到層高為1,即沒有子節點為止
    pp = p;
    if (tsize < height * 3 / 2) {//最後一個元素在左子樹中
        p = p->leftChild;
        tsize -= height / 2
; } else {//最後一個元素在右子樹中 p = p->rightChild; tsize -= height; } height /= 2; }

進行完上述過程後,p就指向最後一個元素,pp就指向了它的父節點,其他步驟就只要像陣列實現的堆一樣實現就可以了。
插入時如果不想像陣列實現一樣從下往上,也可以把插入過程融合到上述過程裡,具體情況可以看我發在最後的程式碼。

堆的初始化在連結串列實現中也不是很簡單,主要是連結串列並不像陣列一樣可以簡單的進行層序訪問。但是,可以採用陣列儲存前size/2個節點,並對該陣列中的元素倒序進行調整,從而滿足O(n)的時間複雜度。

template<class T>
void MaxHeap<T>::Initialize(T a[], int size)
{
    ClearHeap(root); //清空原先的樹
    this->size = size;

    if (size == 0) return;

    HeapNode<T> **insideNode = new HeapNode<T>*[size / 2]; //定義一個儲存前size/2個節點的陣列
    HeapNode<T> *currentNode;
    HeapNode<T> *tmp;//存放當前放入元素的節點
    int index = 0; //insideNode陣列的索引

    //初始化根節點
    root = new HeapNode<T>(a[0]);
    insideNode[0] = root;
    currentNode = root;

    for (int i = 1; i < size; i++) {
        if (!currentNode->leftChild) {//左節點為空
            currentNode->leftChild = new HeapNode<T>(a[i]);
            tmp = currentNode->leftChild;
        }
        else if (!currentNode->rightChild) {//右節點為空
            currentNode->rightChild = new HeapNode<T>(a[i]);
            tmp = currentNode->rightChild;
        }
        else {//左右節點都滿
            index++;
            currentNode = insideNode[index];
            currentNode->leftChild = new HeapNode<T>(a[i]);
            tmp = currentNode->leftChild;
        }
        if (i < size / 2) //如果陣列元素下標小於size/2,則放入insideNode陣列中
            insideNode[i] = tmp;
    }

    HeapNode<T> *pp = 0;//當前節點的上一個節點
    //對interNode中的節點從最後一個開始進行調整
    for (; index >= 0; index--) {
        tmp = insideNode[index];
        T y = tmp->data;
        while (tmp) {
            pp = tmp;
            if (tmp->rightChild&&tmp->leftChild->data < tmp->rightChild->data)
                tmp = tmp->rightChild;
            else
                tmp = tmp->leftChild;
            if (!tmp || y > tmp->data) break;//當tmp為空或y比tmp內元素大時跳出
            pp->data = tmp->data;
        }
        pp->data = y;
    }
    delete[] insideNode;
}

霍夫曼樹,即有最小WEP(加權外部路徑長度,weighted external path length)的樹,可以用於生成元素的霍夫曼編碼。就是把兩個權重最小的數構成一棵新的樹,放回序列中,再重複這個過程,直到只剩下一棵樹,通過對這棵樹進行解析就可以得到霍夫曼編碼了。因為是要取最小數,可以將權重加上負號而使用最大堆,也可以再寫一個最小堆。解析方式可以參考我放在最後的程式碼中的BinaryTree.cpp裡的方法。

二叉搜尋樹就比較簡單了,只要小的就放左邊,大的放右邊就可以了,可以直接看程式碼。

相關推薦

搜尋連結串列實現

目的: 1、建立最大堆類。最大堆的儲存結構使用連結串列。 2、提供操作:堆的插入、堆的刪除。堆的初始化。Huffman 樹的構造。二叉搜尋樹的構造。 3、接收鍵盤錄入的一系列整數,輸出其對應的最大堆、Huffman 編碼以及二叉搜尋樹。 4、堆排序。

分別用陣列連結串列實現

    為了更好的理解棧的原理,本文分別用陣列和連結串列實現了棧,     1 陣列實現棧: /* @ brife:陣列實現棧類 */ #include <Windows.h> #ifndef ARRAYSTACK_H #define ARRAYST

佇列類(分別用列表連結串列實現

#!/usr/bin/python3 class QueueUnderflow(ValueError):     pass class ListQueue():  #列表實現迴圈佇列類     def __init__(self, len_

棧類(分別用列表連結串列實現

#!/usr/bin/python3 class StackUnderflow(ValueError):     pass class ListStack():     def __init__(self):      

用陣列連結串列實現

完成一個棧總共需要完成以下操作:初始化入棧出棧檢視棧頂元素檢視棧的容量清空棧。首先是簡單的,用陣列做的,會有越界的可能。#include <stdio.h> #include <stdlib.h> typedef struct Stack {

c++分別用陣列連結串列實現棧的操作

棧在實際程式設計中經常會用到,本文利用陣列和連結串列分別實現了棧的操作。 1.陣列方式實現如下: #include<iostream> using namespace std; template <class T> class arraysta

佇列的陣列連結串列實現

1.佇列是先入先出額資料結構,它的實現可以用陣列,也可以用連結串列。用陣列實現連結串列時,需要預先分配陣列的大小,用front和rear下標分別表示隊頭元素下標和隊尾元素下標,插入一個元素時,使隊尾的下標rear加1,刪除一個元素時,front下標加1,判斷是否為空的佇列只

線性表的陣列實現連結串列實現

線性表的順序儲存實現 //線性表用陣列來實現 typedef struct PolyNode *Polynomial; struct PolyNode{ int coef;//係數 int expon;//exponential指數 Polynomial

劍指offer——二叉搜尋雙向連結串列

劍指offer題越往後感覺越不好做呀,本來是不會做,現在是難看懂了,乍一眼看這個題,二叉搜尋樹 ,先把樹給拆了,然後排個序,最後加個鏈。不過實現還是不太容易的。 class Solution: def Convert(self,pRootOfTree): if n

二叉C++ | 連結串列遞迴實現二叉(插入、搜尋)_1

遞迴實現二叉樹(插入、搜尋) // Binary Search Tree - Implemenation in C++ // Simple program to create a BST of integers and search an element in it #include<i

陣列連結串列與棧佇列之間的關係及棧之間的關係

本屌最近在學習資料結構過程中,由於連續看了陣列,棧,佇列,連結串列等,一時混雜,下面摘取參考資料,供自己學習使用。 第一部分:介紹了資料儲存結構和資料結構的區別,以及連結串列和陣列的差異。 第二部分:介紹了堆和棧的區別。 (1)資料儲存結構:計算機的一個概念,描述資料在計算機中儲存方式;常用

【Java基礎-實現連結串列】定義連結串列連結串列的遍歷

一.定義一個節點 建立一個節點類,類中定義兩個屬性,一個屬性用來存放資料,一個屬性用來存放下一個節點 class Node { String data = null; //連結串列儲存的資料 Node next = null; //下一個節點 public Node (

一元多項式求和的兩種實現(陣列連結串列

一元多項式求和一般都是有兩種實現方式,小編下面就附上我對這兩種方式的理解和實現程式碼。 1.陣列實現。這種方式實現一元多項式加法,是把陣列下標當做一元多項式的指數,在陣列中存放係數。這種方式在實現一元多項是加法是通過遍歷陣列下標來獲取指數資訊,通過指數資訊將係數進行相加。利用陣列在實現一元多項式

陣列連結串列集合的區別應用場景以及棧的區別

陣列和集合的區別: 1.陣列的長度固定的,超過長度時,只能建立一個新的陣列,並把舊的陣列的值傳進去方可; 而集合的長度是動態不固定的。 2.陣列的儲存型別是單一的,同一陣列只能儲存同一資料型別的資料。 而集合可以儲存多鍾資料型別的資料。 3.陣列只能通過下標來訪

C++實現陣列連結串列的排序演算法

OK,我們經常會用到排序演算法。那麼,常用的排序演算法,除了使用陣列之外,用連結串列又該如何處理呢?下面我們來做個對比: //使用插入排序對陣列進行排序 int *get_order(int *num, int length) { for(int eiter = 1; eiter <

模板實現順序表連結串列

順序表的實現:"Seqlist.h"  #pragma once template<class T> class Seqlist { private: T* _array; size_t _size; size_t _capacity; public:

統計難題 HDU - 1251 -字典-連結串列實現

統計難題  HDU - 1251  題意:輸入資料的第一部分是一張單詞表,每行一個單詞,單詞的長度不超過10,它們代表的是老師交給Ignatius統計的單詞 ,一個空行代表單詞表的結束.第二部分是一連串的提問,每行一個提問,每個提問都是一個字串

基於陣列連結串列兩種方式實現

棧是一種先進後出的資料結構,在實際程式設計棧有很廣泛的用處,Java棧已經幫我們實現好了stack類。 實現棧的兩種方式,基於陣列實現和基於連結串列實現。 1.stack介面 public interface StackADT { //入棧操作 public voi

C++模板的實現(模板函式模板類,附帶模板實現順序表連結串列程式碼)

模板  當我們實現一個交換函式時,我們可以寫成如下。 void Swap(int& x, int& y) { int tmp = x; x = y; y = tmp; }  這裡只能交換兩個整數,當我們

使用陣列連結串列的方式實現

使用 陣列和連結串列 的方式實現 棧 陣列實現棧: public class Stack<Item> implements Iterable<Item> { pri