基於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、除根結