1. 程式人生 > >基於QT Creator的紅黑樹

基於QT Creator的紅黑樹

採用QT的按鈕實現插入刪除等控制,採用QT的文字框輸出紅黑樹。

main.cpp

#include "mainwindow.h"
#include <QApplication>
#include "rbtree.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.setWindowTitle("RedBlackTree");
    w.setObjectName("MainWindow");
    w.setStyleSheet("#MainWindow{border-image:url(C://Users//zhangyq//Desktop//bg.png);}");
    w.show();

    return a.exec();
}

mainwiindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

bool MainWindow::GetNum(int &i)   //獲得鍵盤輸入的資料
{
    bool ok;
    i = QInputDialog::getInt(this, tr("Prossing..."),
        tr("Number: "), 0, 0, 1000, 1, &ok);
    if(!ok) return false;
    return true;
}

void MainWindow::on_AddBtn_clicked()   //Add槽函式
{
    int num;

    if(!GetNum(num)) return;   //未輸入資料,則直接結束

    if(t.find(num))  //如果資料已經存在,根據紅黑樹的定義,樹中不能出現相同節點,此時向用戶反饋錯誤資訊
        QMessageBox::warning(this, tr("Warning"), tr("Number Existing!"),QMessageBox::Abort);

    t.insert(num);  //插入

    QString str;

    t.print(str);   //顯示

    ui->DisplyEdit->setText(str);

}

void MainWindow::on_DelBtn_clicked()  //Deleet槽函式
{
    int num;

    if(!GetNum(num)) return;  //未輸入資料,則直接結束

    if(!t.find(num))     //如果樹中無此節點,向用戶反饋錯誤資訊
        QMessageBox::warning(this, tr("Warning"), tr("Can't Find!"),QMessageBox::Abort);

    t.erase(num);   //刪除

    QString str;

    t.print(str);  //顯示

    ui->DisplyEdit->setText(str);

}

void MainWindow::on_ResetBtn_clicked()   //Clear槽函式
{
    t.destroy(t.root());   //銷燬紅黑紅樹,釋放節點
    t.root() = nullptr;
    ui->DisplyEdit->setText("");
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QInputDialog>
#include <rbtree.h>
#include <QString>
#include <QMessageBox>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    bool GetNum(int &);  //獲取輸入資料

private slots:
    void on_AddBtn_clicked();    //Add槽函式

    void on_DelBtn_clicked();    //Delete槽函式

    void on_ResetBtn_clicked();  //Clear槽函式

private:
    RBTree t;
    Ui::MainWindow *ui;

};

#endif // MAINWINDOW_H

rbtree.cpp

#include "rbtree.h"

void RBTree::rotate_left(Node * x)   //左旋,用於重構
{
    Node * y = x->right;   //以右子節點為支點旋轉

    x->right = y->left;
    if (y->left)
        y->left->parent = x;
    y->parent = x->parent;

    if (x == root())
        root() = y;
    else if (x == x->parent->left)
        x->parent->left = y;
    else
        x->parent->right = y;

    y->left = x;
    x->parent = y;
}

void RBTree::rotate_right(Node * x)   //右旋,用於重構
{
    Node * y = x->left;    //以左子節點為支點旋轉

    x->left = y->right;
    if (y->right)
        y->right->parent = x;
    y->parent = x->parent;

    if (x == root())
        root() = y;
    else if (x == x->parent->right)
        x->parent->right = y;
    else
        x->parent->left = y;

    y->right = x;
    x->parent = y;
}

void RBTree::destroy(Node * node)   //樹的銷燬
{
    if (node == nullptr)
        return;

    destroy(node->left);  //銷燬左孩子
    destroy(node->right); //銷燬右孩子
    delete node;  //釋放節點
}

Node *& RBTree::root()
{
    return header->left;  //head->l=root
}

void RBTree::insert_rebalance(Node * x)  //插入後重構
{
    x->color = red;

    while (x != root() && x->parent->color == red)  //父親節點是紅色時重構
    {
        if (x->parent == x->parent->parent->left)
        {
            Node * y = x->parent->parent->right;

            if (y && y->color == red)           // Case 1 叔叔節點為紅色
            {
                x->parent->color = black;
                y->color = black;
                x->parent->parent->color = red;
                x = x->parent->parent;
            }
            else    //叔叔節點黑色
            {
                if (x == x->parent->right)      // Case 2當前節點為其父親節點右孩子
                {
                    x = x->parent;
                    rotate_left(x);
                }

                x->parent->color = black;       // Case 3當前節點為其父親節點左孩子
                x->parent->parent->color = red;
                rotate_right(x->parent->parent);
            }
        }
        else  //和上面相同,映象操作
        {
            Node * y = x->parent->parent->left;

            if (y && y->color == red)
            {
                x->parent->color = black;
                y->color = black;
                x->parent->parent->color = red;
                x = x->parent->parent;
            }
            else
            {
                if (x == x->parent->left)
                {
                    x = x->parent;
                    rotate_right(x);
                }

                x->parent->color = black;
                x->parent->parent->color = red;
                rotate_left(x->parent->parent);
            }
        }
    }

    root()->color = black;  //最後根節點重新著色為黑色
}

void RBTree::erase_rebalance(Node * z)  //刪除後重構
{
    Node * y = z;
    Node * x = nullptr;
    Node * x_parent = nullptr;

    if (y->left == nullptr)
        x = y->right;
    else if (y->right == nullptr)
        x = y->left;
    else
    {
        y = y->right;   //找右子樹最小節點
        while (y->left)
            y = y->left;
        x = y->right;
    }

    if (y != z)  //y是z的祖先// the third
    {
        z->left->parent = y;
        y->left = z->left;

        if (y != z->right)
        {
            x_parent = y->parent;
            if (x)
                x->parent = y->parent;
            y->parent->left = x;
            y->right = z->right;
            z->right->parent = y;
        }
        else
            x_parent = y;

        if (root() == z)
            root() = y;
        else if (z->parent->left == z)
            z->parent->left = y;
        else
            z->parent->right = y;

        y->parent = z->parent;
        swap(y->color, z->color);
        y = z;
    }
    else
    {
        x_parent = y->parent;
        if (x)
            x->parent = y->parent;

        if (root() == z)
            root() = x;
        else if (z->parent->left == z)
            z->parent->left = x;
        else
            z->parent->right = x;
    }
    //現在,y是想要刪除的節點!
    //  x是y的子節點,x必須是空節點



    // 重構的實現
    // .....
    if (y->color == black)
    {
        while (x != root() && (x == nullptr || x->color == black))
        {
            if (x == x_parent->left)
            {
                Node * w = x_parent->right;  // w can not possibly be nullptr!

                if (w->color == red)                                      // Case 1當前結點是黑色,兄弟結點是紅色
                {
                    w->color = black;
                    x_parent->color = red;
                    rotate_left(x_parent);
                    w = x_parent->right;
                }

                if ((w->left == nullptr || w->left->color == black) && // Case 2當前結點是黑色,兄弟結點是黑色,兩個孩子為空或是黑色
                    (w->right == nullptr || w->right->color == black))
                {
                    w->color = red;
                    x = x_parent;
                    x_parent = x_parent->parent;
                }
                else
                {
                    if (w->right == nullptr || w->right->color == black)//Case 3
                    {                                //當前結點是黑色,兄弟結點是黑色,兄弟結點的左孩子是紅色,右孩子為空或是黑色
                        if (w->left)
                            w->left->color = black;
                        w->color = red;
                        rotate_right(w);
                        w = x_parent->right;
                    }

                    w->color = x_parent->color;  // Case 4
                    x_parent->color = black;     //當前結點是黑色,兄弟結點是黑色,兄弟結點的右孩子是紅色,左孩子為空或紅黑皆可
                    if (w->right)
                        w->right->color = black;
                    rotate_left(x_parent);
                    break;
                }
            }
            else  //和上面相同,映象操作
            {
                Node * w = x_parent->left;

                if (w->color == red)
                {
                    w->color = black;
                    x_parent->color = red;
                    rotate_right(x_parent);
                    w = x_parent->left;
                }

                if ((w->right == nullptr || w->right->color == black) &&
                    (w->left == nullptr || w->left->color == black))
                {
                    w->color = red;
                    x = x_parent;
                    x_parent = x_parent->parent;
                }
                else
                {
                    if (w->left == nullptr || w->left->color == black)
                    {
                        if (w->right)
                            w->right->color = black;
                        w->color = red;
                        rotate_left(w);
                        w = x_parent->left;
                    }

                    w->color = x_parent->color;
                    x_parent->color = black;
                    if (w->left)
                        w->left->color = black;
                    rotate_right(x_parent);
                    break;
                }
            }
        }  // while (x != root() && (x == nullptr || x->color == black))

        if (x)
            x->color = black;
    }  // if (y->color == black)
}

RBTree::RBTree()
{
    header = new Node(0);
}

RBTree::~RBTree()
{
    destroy(root());
    delete header;
    header = nullptr;
}

Node * RBTree::insert(int key)  //插入
{
    Node * cur = root();
    Node * pre = header;

    while (cur)
    {
        pre = cur;
        if (key < cur->key)
            cur = cur->left;
        else if (key > cur->key)
            cur = cur->right;
        else
            return nullptr;
    }

    cur = new Node(key);
    cur->parent = pre;

    if (pre == header || key < pre->key)
        pre->left = cur;
    else
        pre->right = cur;

    insert_rebalance(cur);  //重構

    return cur;
}

Node * RBTree::find(int key) //查詢
{
    Node * z = root();

    while (z)
    {
        if (key < z->key)
            z = z->left;
        else if (key > z->key) //和二叉排序樹相同
            z = z->right;
        else
            return z;
    }

    return z;
}

void RBTree::erase(int key)  //刪除
{
    Node * z = find(key);

    if (z)
    {
        erase_rebalance(z); //重構
        delete z;
    }
}

void RBTree::doprint(Node *T, int level, QString &str)
{
    if (T == nullptr) return;        //如果指標為空,返回上一層

    doprint(T->right, level + 1, str);   //列印右子樹,並將層次加1
    for (int i = 0; i<level; i++)    //按照遞迴的層次列印空格
    {
        str += "    ";//printf("   ");
    }
    char num[10];

    sprintf(num, "%d", T->key);
    str += QString(num);

    str += (T->color == red) ? "R\n\n" : "B\n\n";
    doprint(T->left, level + 1, str);    //列印左子樹,並將層次加1
    str += "\n";
}

void RBTree::print(QString &str)
{

    doprint(this->root(), 1, str);

}

rbtree.h

#ifndef RBTREE_H
#define RBTREE_H

#include <iostream>
#include <algorithm>
#include <QString>

using namespace std;

enum { red = 0, black = 1 };

struct Node         //採用三叉連結串列表示樹的節點
{
    int key;
    bool color;
    Node * parent;
    Node * left;
    Node * right;
    Node(int key = 0)
    {
        this->key = key;
        this->color = red;
        this->parent = this->left = this->right = nullptr;
    }
};

class RBTree
{
private:
    Node * header; //head->l = root
private:
    void rotate_left(Node * x);       //左旋,用於重構
    void rotate_right(Node * x);      //右旋,用於重構
    void insert_rebalance(Node * x);  //插入後重構
    void erase_rebalance(Node * z);   //刪除後重構

public:
    RBTree();
    ~RBTree();
    Node * insert(int key);      //插入
    Node * find(int key);        //查詢
    Node *& root();       //得到根節點
    void destroy(Node * node);   //樹的銷燬
    void erase(int key);         //刪除
    void print(QString &);       //樹形列印
    void doprint(Node *t, int level, QString &);
};

#endif // RBTREE_H

相關推薦

基於Java實現的基本操作

首先,在閱讀文章之前,我希望讀者對二叉樹有一定的瞭解,因為紅黑樹的本質就是一顆二叉樹。所以本篇部落格中不在將二叉樹的增刪查的基本操作了。 有隨機數節點組成的二叉樹的平均高度為logn,所以正常情況下二叉樹查詢的時間複雜度為O(logn)。但是,根據二叉樹的特性,在最壞的情況下,比如儲存的是一個有

基於QT Creator

採用QT的按鈕實現插入刪除等控制,採用QT的文字框輸出紅黑樹。 main.cpp #include "mainwindow.h" #include <QApplication> #include "rbtree.h" int main(int argc, c

基於的查詢(二叉排序、平衡二叉、B、B+、伸展)

本文主要介紹幾種比較重要的樹形結構: ① 二叉排序樹 ② 平衡二叉樹 ③ B樹 ④ B+樹 ⑤ 伸展樹 ⑥ 紅黑樹 分為三個問題來描述每種樹: ① 是什麼?主要應用? ② 有什麼特點(性質)? ③ 基於它的操作?

Java 基於的TreeMap,TreeSet實現原理

TreeSet and TreeMap 總體介紹 之所以把TreeSet和TreeMap放在一起講解,是因為二者在Java裡有著相同的實現,前者僅僅是對後者做了一層包裝,也就是說TreeSet裡面有一個TreeMap(介面卡模式)**。因此本文將重點分析TreeMap。

【bzoj3227】

發現 blog ret amp 這樣的 spa 兩個 include log 神TM的紅黑樹,其實本質上應該還是一種樹dp的問題…… 一開始想了一個比較裸的樹dp,後來發現還有更強的做法。 每個前端黑節點是看作一個物品,然後這就是很典型的樹形dp的問題。 不過可以這麽考慮,

圖解集合7:概念、的插入及旋轉操作詳細解讀

集合 得到 2個 排序。 數據流 except boolean 修正 split 原文地址http://www.cnblogs.com/xrq730/p/6867924.html,轉載請註明出處,謝謝! 初識TreeMap 之前的文章講解了兩種Map,分別是HashMa

C++實現

con colors end ase 復制代碼 設置 typename ucc 技術 1 /* 2 * rbtree.h 3 * 1. 每個節點是紅色或者黑色 4 * 2. 根節點是黑色 5 * 3. 每個葉子節點是黑色(該葉子節點就空的節點)

數據結構學習筆記-排序/隊/棧/鏈/堆/查找/

算法 數據結構排序:插入排序:每次從剩余數據中選取一個最小的,插入已經排序完成的序列中合並排序:將數據分成左右兩組分別排序,然後合並,對每組數據的排序遞歸處理。冒泡排序:重復交換兩個相鄰元素,從a[1]開始向a[0]方向冒泡,然後a[2]...當a[i]無法繼續往前擠的時候說明前面的更小了,而且越往前越小(擠

查找(一)史上最簡單清晰的解說

ont 演示 detail align article 向上 節點 動態插入 列表 查找(一) 我們使用符號表這個詞來描寫敘述一張抽象的表格。我們會將信息(值)存儲在當中,然後依照指定的鍵來搜索並獲取這些信息。鍵和值的詳細意義取決於不同的應用。 符號表中可能會保

教你透徹了解

black ade 我們 工作 key 針對 otn strong lean 教你透徹了解紅黑樹 作者:July、saturnman 2010年12月29日 本文參考:Google、算法導論、STL源碼剖析、計算機程序設計藝術。 推薦閱讀: Left-

else if 滿足 編碼 使用 由於 imap ica 困難 十分 轉自:http://www.cnblogs.com/yangecnu/p/Introduce-2-3-Search-Tree.html 前面一篇文章介紹了2-3查找樹,可以看到,2-3查找樹能保證在插

與AVL

target 相同 spa search htm 解決 evel 所有應用 二叉搜索樹 概述:本文從排序二叉樹作為引子,講解了紅黑樹,最後把紅黑樹和AVL樹做了一個比較全面的對比。 1 排序二叉樹 排序二叉樹是一種特殊結構的二叉樹,可以非常方便地對樹中所有節點進行排

------ luogu P3369 【模板】普通平衡(Treap/SBT)

div child lin main false tchar clas char als 二次聯通門 : luogu P3369 【模板】普通平衡樹(Treap/SBT) 近幾天閑來無事。。。就把各種平衡樹都寫了一下。。。 下面是紅黑樹(Red Black Tree)

關聯容器set的用法(關聯容器,,)

ise 特定 using iter tor pre .com main com set和multiset會根據特定的排序準則自動將元素排序,set中元素不允許重復,multiset可以重復。// 2017/7/23號 好像set容器裏面只能裝一個元素#include<

關聯容器map(,key/value)

數值 logs items image 劃線 tor tar 參數 cde 字符串或串(String)是由數字、字母、下劃線組成的一串字符。一般記為 s=“a1a2···an”(n>=0)。它是編程語言中表示文本的數據類型。在程序設計中,字符

數據結構與算法-

數據結構 插入 搜索 節點 二叉排序樹 破壞 最長路徑 成了 art 前言 紅黑樹是工程中最常用到的一種自平衡二叉排序樹,其和AVL樹類似,都是在進行插入、刪除時通過一定的調整操作來維持相對穩定的樹高,從而獲得較好的查詢性能。 性質 1. 節點是紅色或黑色。 2. 根節點是

之添加節點和創建

left 理解 算法導論 case 問題 col cas 代碼 htm 紅黑樹之插入節點 紅黑樹的性質 紅黑樹是每個節點都帶有顏色屬性的二叉查找樹,顏色或紅色或黑色。在二叉查找樹強制一般要求以外,對於任何有效的紅黑樹我們增加了如下的額外要求: 節點是紅色或黑色。

之刪除節點

易到 特定 1-1 enter 來看 紅孩子 簡單 code 排序 紅黑樹之刪除節點 上一篇文章中講了如何向紅黑樹中添加節點,也順便創建了一棵紅黑樹。今天寫寫怎樣從紅黑樹中刪除節點。 相比於添加節點,刪除節點要復雜的多。不過我們慢慢梳理,還是能夠弄明白的。 回顧一下紅黑樹的

數據結構 -

必須 現在 管理 對稱 集合 不一定 處理 轉變 .com 紅黑樹(一)之 原理和算法詳細介紹 R-B Tree簡介 R-B Tree,全稱是Red-Black Tree,又稱為“紅黑樹”,它一種特殊的二叉查找樹。紅黑樹的每個節點上都有存儲位表示節點的顏色,可以

B、B+、AVL

付出 而不是 通過 找到 磁盤讀寫 三次 復雜度 節點 span 定義及概念 B樹 二叉樹的深度較大,在查找時會造成I/O讀寫頻繁,查詢效率低下,所以引入了多叉樹的結構,也就是B樹。階為M的B樹具有以下性質: 1、根節點在不為葉子節點的情況下兒子數為 2 ~ M2、除根結