C語言數(shù)據(jù)結(jié)構(gòu)之平衡二叉樹(AVL樹)實(shí)現(xiàn)方法示例
本文實(shí)例講述了C語言數(shù)據(jù)結(jié)構(gòu)之平衡二叉樹(AVL樹)實(shí)現(xiàn)方法。分享給大家供大家參考,具體如下:
AVL樹是每個(gè)結(jié)點(diǎn)的左子樹和右子樹的高度最多差1的二叉查找樹。
要維持這個(gè)樹,必須在插入和刪除的時(shí)候都檢測(cè)是否出現(xiàn)破壞樹結(jié)構(gòu)的情況。然后立刻進(jìn)行調(diào)整。
看了好久,網(wǎng)上各種各種的AVL樹,千奇百怪。
關(guān)鍵是要理解插入的時(shí)候旋轉(zhuǎn)的概念。
//
// AvlTree.h
// HelloWorld
// Created by feiyin001 on 17/1/9.
// Copyright (c) 2017年 FableGame. All rights reserved.
//
#ifndef __HelloWorld__AvlTree__
#define __HelloWorld__AvlTree__
#include <iostream>
namespace Fable
{
int max(int a, int b)
{
return a > b? a:b;
}
//二叉查找樹,對(duì)于Comparable,必須實(shí)現(xiàn)了><=的比較
template<typename Comparable>
class AvlTree
{
public:
//構(gòu)造函數(shù)
AvlTree(){}
//復(fù)制構(gòu)造函數(shù)
AvlTree(const AvlTree& rhs)
{
root = clone(rhs.root);
}
//析構(gòu)函數(shù)
~AvlTree()
{
makeEmpty(root);
}
//復(fù)制賦值運(yùn)算符
const AvlTree& operator=(const AvlTree& rhs)
{
if (this != &rhs)
{
makeEmpty(root);//先清除
root = clone(rhs.root);//再復(fù)制
}
return *this;
}
//查找最小的對(duì)象
const Comparable& findMin()const
{
findMin(root);
}
//查找最大的對(duì)象
const Comparable& findMax()const
{
findMax(root);
}
//是否包含了某個(gè)對(duì)象
bool contains(const Comparable& x)const
{
return contains(x, root);
}
//樹為空
bool isEmpty()const
{
return root == nullptr;
}
//打印整棵樹
void printTree()const
{
printTree(root);
}
//清空樹
void makeEmpty()
{
makeEmpty(root);
}
//插入某個(gè)對(duì)象
void insert(const Comparable& x)
{
insert(x, root);
}
//移除某個(gè)對(duì)象
void remove(const Comparable& x)
{
remove(x, root);
}
private:
struct AvlNode
{
Comparable element;
AvlNode* left;
AvlNode* right;
int height;
AvlNode(const Comparable& theElement, AvlNode* lt, AvlNode* rt, int h = 0)
:element(theElement), left(lt), right(rt), height(h){}
};
typedef AvlNode* AvlNodePtr;
AvlNodePtr root;//根結(jié)點(diǎn)
//順時(shí)針旋轉(zhuǎn)
void clockwiseRotate(AvlNodePtr& a)
{
AvlNodePtr b = a->left;//左葉子
a->left = b->right;//a的左葉子變?yōu)閎的右葉子,b本來的子結(jié)點(diǎn)都比a小的。
b->right = a;//b的右結(jié)點(diǎn)指向a,b的高度上升了。
a->height = max(height(a->left), height(a->right)) + 1;//重新計(jì)算a的高度
b->height = max(height(b->left), a->height) + 1;//重新計(jì)算b的高度
a = b;//a的位置現(xiàn)在是b,當(dāng)前的根結(jié)點(diǎn)
}
//逆時(shí)針旋轉(zhuǎn)
void antiClockWiseRotate(AvlNodePtr& a)
{
AvlNodePtr b = a->right;//右結(jié)點(diǎn)
a->right = b->left;//a接收b的左結(jié)點(diǎn)
b->left = a;//自己成為b的左結(jié)點(diǎn)
a->height = max(height(a->left), height(a->right)) + 1;//計(jì)算高度
b->height = max(b->height, height(a->right)) + 1;//計(jì)算高度
a = b;//新的根結(jié)點(diǎn)
}
//對(duì)左邊結(jié)點(diǎn)的雙旋轉(zhuǎn)
void doubleWithLeftChild(AvlNodePtr& k3)
{
antiClockWiseRotate(k3->left);//逆時(shí)針旋轉(zhuǎn)左結(jié)點(diǎn)
clockwiseRotate(k3);//順時(shí)針旋轉(zhuǎn)自身
}
//對(duì)右邊結(jié)點(diǎn)的雙旋轉(zhuǎn)
void doubleWithRightChild(AvlNodePtr& k3)
{
clockwiseRotate(k3->right);//順時(shí)針旋轉(zhuǎn)有節(jié)點(diǎn)
antiClockWiseRotate(k3);//逆時(shí)針旋轉(zhuǎn)自身
}
//插入對(duì)象,這里使用了引用
void insert(const Comparable& x, AvlNodePtr& t)
{
if (!t)
{
t = new AvlNode(x, nullptr, nullptr);
}
else if (x < t->element)
{
insert(x, t->left);//比根結(jié)點(diǎn)小,插入左邊
if (height(t->left) - height(t->right) == 2)//高度差達(dá)到2了
{
if (x < t->left->element)//插入左邊
{
clockwiseRotate(t);//順時(shí)針旋轉(zhuǎn)
}
else
{
doubleWithLeftChild(t);//雙旋轉(zhuǎn)
}
}
}
else if (x > t->element)
{
insert(x, t->right);//比根結(jié)點(diǎn)大,插入右邊
if (height(t->right) - height(t->left) == 2)//高度差達(dá)到2
{
if (t->right->element < x)//插入右邊
{
antiClockWiseRotate(t);//旋轉(zhuǎn)
}
else
{
doubleWithRightChild(t);//雙旋轉(zhuǎn)
}
}
}
else
{
//相同的
}
t->height = max(height(t->left), height(t->right)) + 1;//計(jì)算結(jié)點(diǎn)的高度
}
void removeMin(AvlNodePtr& x, AvlNodePtr& t)const
{
if (!t)
{
return;//找不到
}
if (t->left)
{
removeMin(t->left);//使用了遞歸的方式
}
else
{
//找到最小的結(jié)點(diǎn)了
x->element = t->element;
AvlNodePtr oldNode = t;
t = t->right;
delete oldNode;//刪除原來要?jiǎng)h除的結(jié)點(diǎn)
}
if (t)
{
t->height = max(height(t->left), height(t->right)) + 1;//計(jì)算結(jié)點(diǎn)的高度
if(height(t->left) - height(t->right) == 2)
{ //如果左兒子高度大于右兒子高度
if(height(t->left->left) >= height(t->left->right))//并且左兒子的左子樹高度大于左兒子的右子樹高度
{
clockwiseRotate(t); //順時(shí)針旋轉(zhuǎn)
}
else
{
doubleWithLeftChild(t);//雙旋轉(zhuǎn)左子樹
}
}
else
{
if(height(t->right->right) - height(t->right->left) == 2) //如果右子樹大于左子樹
{
antiClockWiseRotate(t);//逆時(shí)針旋轉(zhuǎn)
}
else
{
doubleWithRright(t);//雙旋轉(zhuǎn)右子樹
}
}
}
}
//刪除某個(gè)對(duì)象,這里必須要引用
void remove(const Comparable& x, AvlNodePtr& t)const
{
if (!t)
{
return;//樹為空
}
else if (x < t->element)
{
remove(x, t->left);//比根結(jié)點(diǎn)小,去左邊查找
}
else if (x > t->element)
{
remove(x, t->right);//比根結(jié)點(diǎn)大,去右邊查找
}
else if (!t->left && !t->right)//找到結(jié)點(diǎn)了,有兩個(gè)葉子
{
removeMin(t, t->right);//這里選擇的方法是刪除右子樹的最小的結(jié)點(diǎn)
}
else
{
AvlNodePtr oldNode = t;
t = (t->left) ? t->left : t->right;//走到這里,t最多只有一個(gè)葉子,將t指向這個(gè)葉子
delete oldNode;//刪除原來要?jiǎng)h除的結(jié)點(diǎn)
}
if (t)
{
t->height = max(height(t->left), height(t->right)) + 1;//計(jì)算結(jié)點(diǎn)的高度
if(height(t->left) - height(t->right) == 2)
{ //如果左兒子高度大于右兒子高度
if(height(t->left->left) >= height(t->left->right))//并且左兒子的左子樹高度大于左兒子的右子樹高度
{
clockwiseRotate(t); //順時(shí)針旋轉(zhuǎn)
}
else
{
doubleWithLeftChild(t);//雙旋轉(zhuǎn)左子樹
}
}
else
{
if(height(t->right->right) - height(t->right->left) == 2) //如果右子樹大于左子樹
{
antiClockWiseRotate(t);//逆時(shí)針旋轉(zhuǎn)
}
else
{
doubleWithRright(t);//雙旋轉(zhuǎn)右子樹
}
}
}
}
//左邊子樹的結(jié)點(diǎn)肯定比當(dāng)前根小的,所以一直往左邊尋找
AvlNodePtr findMin(AvlNodePtr t)const
{
if (!t)
{
return nullptr;//找不到
}
if (!t->left)
{
return t;
}
return findMin(t->left);//使用了遞歸的方式
}
//右邊子樹的結(jié)點(diǎn)肯定比當(dāng)前根大,所以一直往右邊找
AvlNodePtr findMax(AvlNodePtr t)const
{
if (t)
{
while (t->right)//使用了循環(huán)的方式
{
t = t->right;
}
}
return t;
}
//判斷是否包含某個(gè)對(duì)象,因?yàn)橐褂眠f歸,所以還有一個(gè)public版本的
bool contains(const Comparable& x, AvlNodePtr t)const
{
if (!t)
{
return false;//空結(jié)點(diǎn)了
}
else if (x < t->element)
{
//根據(jù)二叉樹的定義,比某個(gè)結(jié)點(diǎn)小的對(duì)象,肯定只能存在與這個(gè)結(jié)點(diǎn)的左邊的子樹
return contains(x, t->left);
}
else if (x > t->element)
{
//根據(jù)二叉樹的定義,比某個(gè)結(jié)點(diǎn)大的對(duì)象,肯定只能存在與這個(gè)結(jié)點(diǎn)的右邊的子樹
return contains(x, t->right);
}
else
{
//相等,就是找到啦。
return true;
}
}
//清空子樹
void makeEmpty(AvlNodePtr& t)
{
if (t)
{
makeEmpty(t->left);//清空左邊
makeEmpty(t->right);//清空右邊
delete t;//釋放自身
}
t = nullptr;//置為空
}
//打印子樹,這里沒有使用復(fù)雜的排位,純屬打印
void printTree(AvlNodePtr t)const
{
if (!t)
{
return;
}
std::cout << t->element << std::endl;//輸出自身的對(duì)象
printTree(t->left);//打印左子樹
printTree(t->right);//打印右子樹
}
AvlNodePtr clone(AvlNodePtr t)const
{
if (!t)
{
return nullptr;
}
return new AvlNode(t->element, clone(t->left), clone(t->right));
}
int height(AvlNodePtr t)const
{
return t == nullptr ? -1 : t->height;
}
};
}
#endif
簡(jiǎn)單測(cè)試一下。
//
// AvlTree.cpp
// HelloWorld
// Created by feiyin001 on 17/1/9.
// Copyright (c) 2017年 FableGame. All rights reserved.
//
#include "AvlTree.h"
using namespace Fable;
int main(int argc, char* argv[])
{
AvlTree<int> a;
for(int i = 0; i < 100; ++i)
{
a.insert(i);
}
return 0;
}
這個(gè)刪除的方法完全是自己寫的,可能不是很高效。
希望本文所述對(duì)大家C語言程序設(shè)計(jì)有所幫助。
上一篇:C語言學(xué)生學(xué)籍管理系統(tǒng)課程設(shè)計(jì)
欄 目:C語言
下一篇:C語言學(xué)生信息管理系統(tǒng)小項(xiàng)目
本文標(biāo)題:C語言數(shù)據(jù)結(jié)構(gòu)之平衡二叉樹(AVL樹)實(shí)現(xiàn)方法示例
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/931.html
您可能感興趣的文章
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用函數(shù)刪除字符
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)式函數(shù)庫
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)數(shù)怎么表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段函數(shù)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排序法函數(shù)
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段函數(shù)
- 04-02C語言中怎么打出三角函數(shù) c語言中怎么打出三角函數(shù)的值
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求階乘


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什


