1. 程式人生 > >C++實現二叉搜尋樹(二叉排序樹)模板類

C++實現二叉搜尋樹(二叉排序樹)模板類

參考了Weiss的資料結構與演算法分析C++描述第三版

在中文版中,第99頁貌似有個錯誤。在4.3.6 平均情況分析中,書上寫的是“直觀地,我們期望前一節所有的操作特別是makeEmpty 和 operator=都花費O(logN)時間,……”,我感覺不太對,因為makeEmpty 和 operator=都遍歷了每個節點,花費應該是O(N)才對,其他的操作,比如查詢元素,查詢最大最小之類的,應該是O(logN)。然後我找了一下英文原版書,是第四版了,原文是“Intuitively, we expect that all of the operations described in this section, except

makeEmpty and copying, should take O(logN)time,......”。原來是翻譯錯誤。應該是“除了makeEmpty 和 operator=都花費O(logN)時間”。

下面記錄一下今天的程式碼

首先是定義了二叉查詢樹的模板:BinarySearchTree.h

#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H
#include<iostream>
using namespace std;

template <typename Comparable>
class BinarySearchTree
{
public:
	BinarySearchTree() :m_root(nullptr){}
	BinarySearchTree(const BinarySearchTree &rhs)
	{
		m_root = clone(rhs.m_root);
	}
	~BinarySearchTree()
	{
		makeEmpty();
	}

	/**
	* 找到樹中的最小值,通過呼叫private的findMin實現遞迴
	*/
	const Comparable & findMin() const
	{
		return findMin(m_root)->element;
	}

	/**
	* 找到樹中的最大值,通過呼叫private的findMax實現遞迴
	*/
	const Comparable & findMax() const
	{
		return findMax(m_root)->element;
	}

	/**
	* 當x找到時返回真,否則返回假 
	* 呼叫了private的那個同名函式,這個是為了遞迴實現
	*(因為private中包含了一個BinaryNode的指標t)
	*/
	bool contains(const Comparable &x) const
	{
		return contains(x, m_root);
	}

	/**
	* 判斷樹是否為空
	*/
	bool isEmpty() const
	{
		return m_root == nullptr;
	}

	/**
	* 把樹遍歷一遍(中序,因為中序可以保證順序輸出)
	*/
	void printTree(ostream & out= cout) const
	{
		if (isEmpty())
			out << "Empty tree!" << endl;
		else
			printTree(m_root, out);
	}

	/**
	* 清空樹
	*/
	void makeEmpty()
	{
		makeEmpty(m_root);
	}

	/**
	* 把x插入樹中,如果重複了就忽略
	*/
	void insert(const Comparable &x)
	{
		insert(x, m_root);
	}

	/**
	* 把x從樹中刪除。如果x不在樹中就什麼都不做。
	*/
	void remove(const Comparable &x)
	{
		remove(x, m_root);
	}

	/**
	* 深拷貝
	*/
	const BinarySearchTree & operator= (const BinarySearchTree &rhs)
	{
		if (this != &rhs)
		{
			BinaryNode *tmp = clone(rhs.m_root);
			makeEmpty();
			m_root = tmp;
		}
		return *this;
	}


private:
	struct BinaryNode{
		Comparable element;
		BinaryNode *left;
		BinaryNode *right;
		
		BinaryNode(const Comparable &theElement,
			BinaryNode *lt,
			BinaryNode *rt)
			: element(theElement), left(lt), right(rt) {}
	};

	BinaryNode *m_root;

	/**
	* 在樹t中插入元素x,如果重複則什麼也不做
	*/
	void insert(const Comparable &x, BinaryNode * &t) const
	{
		if (t == nullptr)
			t = new BinaryNode(x, nullptr, nullptr);
		else if (x < t->element)
			insert(x, t->left);
		else if (t->element < x)
			insert(x, t->right);
		else
			; // 表示在樹中找到了x,則什麼也不做
	}

	/**
	* 在樹t中刪除元素x
	*/
	void remove(const Comparable &x, BinaryNode * &t) const
	{
		if (t == nullptr)
			return; // 沒有找要刪除的節點x
		if (x < t->element)
			remove(x, t->left);
		else if (t->element < x)
			remove(x, t->right);
		else if (t->left != nullptr &&
		t->right != nullptr)
		{
			t->element = findMin(t->right)->element;
			remove(t->element, t->right);
		}
		else
		{
			BinaryNode * oldNode = t;
			t = (t->left != nullptr) ? t->left : t->right;
			delete oldNode;
		}
	}

	/**
	* 查詢最小的元素, 通過遞迴的方法
	*/
	BinaryNode * findMin(BinaryNode *t) const
	{
		if (t == nullptr)
			return nullptr;
		if (t->left == nullptr)
			return t;
		return findMin(t->left);
	}

	/**
	* 查詢最大的元素, 通過迴圈的方法
	*/
	BinaryNode * findMax(BinaryNode *t) const
	{
		if (t != nullptr)
			while (t->right != nullptr)
				t = t->right;
		return t;
	}

	/**
	* 通過遍歷的方法查詢x是否在樹(或子樹)t中
	*/
	bool contains(const Comparable &x, BinaryNode * t) const
	{
		if (t == nullptr) // 遍歷中未找到元素的中止條件
			return false;
		else if (x < t->element)
			return contains(x, t->left);
		else if (t->element < x)
			return contains(x, t->right);
		else // 如果 x 不大於 也 不小於t所指的節點中的元素,則x==t->element
			return true;
	}

	/**
	* 清空樹
	*/
	void makeEmpty(BinaryNode * &t)
	{
		if (t != nullptr)
		{
			makeEmpty(t->left);
			makeEmpty(t->right);
			delete t;
		}
		t = nullptr;
	}

	/**
	* 列印子樹
	*/
	void printTree(BinaryNode *t, ostream & out) const
	{
		if (nullptr != t)
		{
			printTree(t->left, out);
			out << t->element << endl;
			printTree(t->right, out);
		}
	}

	/**
	* 複製子樹
	*/
	BinaryNode * clone(BinaryNode *t) const
	{
		if (t == nullptr)
			return nullptr;

		return new BinaryNode(t->element, clone(t->left), clone(t->right));
	}

};
#endif
測試用的文件:testDemo.cpp
#include<iostream>
#include<random>
#include<ctime>
using namespace std;

#include"BinarySearchTree.h"

int main()
{
	BinarySearchTree<int> t; // 建立一個二叉搜尋樹

	uniform_int_distribution<unsigned int> u(0,200); // 設定隨機數分佈
	default_random_engine e(time(0)); // 設定隨機數引擎(通過時間作為種子)

	cout << "==== 測試插入:" << endl;
	for (size_t i = 0; i < 8; ++i)
	{
		t.insert(u(e));
	}
	cout << "==== 測試列印:"<< endl;
	t.printTree();
	cout << "==== 測設刪除(刪除小於100的數):" << endl;
	for (size_t i = 0; i < 100; ++i)
	{
		t.remove(i);
	}
	t.printTree();
	cout << "==== 測試拷貝建構函式:" << endl;
	BinarySearchTree<int> t2(t);
	t2.printTree();
	cout << "==== 測試賦值操作:" << endl;
	BinarySearchTree<int> t3;
	t3 = t;
	t.printTree();
	cout << "==== 測試最大最小值:" << endl;
	cout << "最大值:" << t.findMax() << endl;
	cout << "最小值:" << t.findMin() << endl;

	return 0;
}

結果如圖:


相關推薦

c#實現的一些幾何演算法

續一 //關於線的一些演算法    public class GeometricClass     {         /* 判斷點與線段的關係,用途很廣泛           本函式是根據下面的公式寫的,P是點C到線段AB所在直線的垂足                

通過C#實現OPC-UA服務端

前言 通過我前面的一篇檔案,我們已經能夠搭建一個OPC-UA服務端了,並且也擁有了一些基礎功能。這一次咱們就來了解一下OPC-UA的服務註冊與發現,如果對服務註冊與發現這個概念不理解的朋友,可以先百度一下,由於近年來微服務架構的興起,服務註冊與發現已經成為一個很時髦的概念,它的主要功能可分為三點:1、服務註冊

C#實現氣泡屏保效果用4個timer

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.

C++實現一個單例模式懶漢與餓漢

單例模式的特點: 1、一個類只能有一個例項。 2、一個類必須自己建立自己的唯一例項。 3、一個類必須給所有其他物件提供這一例項。 單例模式的實現: 1、將建構函式宣告為private防止被外部

C++實現搜尋排序模板

參考了Weiss的資料結構與演算法分析C++描述第三版 在中文版中,第99頁貌似有個錯誤。在4.3.6 平均情況分析中,書上寫的是“直觀地,我們期望前一節所有的操作特別是makeEmpty 和 operator=都花費O(logN)時間,……”,我感覺不太對,因為make

基礎操作 ,前中後序遍歷,求高度,搜尋排序Java實現 程式碼集合

首先,定義一個樹類Tree.java public class Tree { public TreeNode root; } 定義樹節點類TreeNode.java public class TreeNode { public TreeNode(int

c語言實現連結串列非遞迴後序遍歷

演算法思想 因為後序遍歷是先訪問左子樹,再訪問右子樹,最後訪問根節點。當用棧實現遍歷時,必須分清返回根節點時,是從左子樹返回的還是從右子樹返回的。所以使用輔助指標r指向最近已訪問的結點。當然也可以在節點中增加一個標誌域,記錄是否已被訪問。 #include<iost

建立完全搜尋Complete Binary Search Tree c++

Complete Binary Search Tree(c++) 因為題目要求,首先輸入二叉樹的結點個數,再輸入每個結點對應的值,建立二叉樹,既是二叉搜尋樹,又是完全二叉樹。 整體思路 根據輸入的結點數,建立完全二叉樹; 將節點數值放在陣列中,從小到大排序;

模板搜尋排序查詢,BST

二叉搜尋樹其實就是滿足左結點小於根,右結點大於根這類規則的樹形結構。  1 int n; 2 int a[MAX_N]; 3 int lt[MAX_N], rt[MAX_N]; 4 // 沒有則為-1 5 // 預設a[0]為根結點 6 7 void Insert(int

查詢排序建立、插入、刪除、查詢-C語言

二叉查詢樹:或者是一顆空樹;或者是具有以下性質的二叉樹:(1)若它的左子樹不為空,則左子樹上所有結點的值都小於根結點的值;(2)若它的右子樹不為空,則右子樹所有結點的值均大於它的根結點的值;(3)左右子樹分別為二叉查詢樹; #include <std

2.判斷一個是否是搜尋騰訊面試題

1.面試的時候當面試官提出來的時候,我立馬想到的就是基於前序遍歷的遞迴方法。但是這個方法在面試官給說一個測試用例的時候就徹底傻眼了。public class Main { public static boolean isSerchBTree(TreeNode root)

排序搜尋

題目大意:現在給你N個關鍵字值各不相同的節點,要求你按順序插入一個初始為空樹的二叉排序樹中,每次插入後成功後,求相應的父親節點的關鍵字值,如果沒有父親節點,則輸出-1。 九度OJ連結:http://ac.jobdu.com/problem.php?pid=1467 分析:二

C++資料結構:——的遍歷

一、序言 在上一篇文章中《二叉樹的先序建立》,我們介紹了二叉樹的基本結構以及先序建立二叉樹,在本篇文章中,我們要對二叉樹進行遍歷,包括: 層序遍歷 遞迴先序遍歷、遞迴中序遍歷、遞迴後序遍歷 非遞迴中序遍歷 二、二叉樹的遍歷 BiTree.h

”據結構一:搜尋Binary Search Tree, BST

前言 定義 來源 演算法 資料結構 查 遍歷 增 刪 總結 參閱 前言 想寫兩篇關於AVL樹和B樹的較為詳細的介紹,發現需要先介紹二叉搜尋樹作為先導。 定義 二叉搜尋樹(Binary Search Thee, BST),也被稱為二

搜尋穿線抽象結構以及線索化演算法

//二叉線索樹 //每個節點儲存了它在某種遍歷順序下的前驅和後繼節點的位置,所以Node類中需要新增 //preLink和nextLink兩個指標,但是在中序遍歷下,可以把未被利用的n+1個指標域用

[LintCode]95.驗證查詢排序搜尋 中序遍歷

給定一個二叉樹,判斷它是否是合法的二叉查詢樹(BST) 一棵BST定義為: 節點的左子樹中的值要嚴格小於該節點的值。節點的右子樹中的值要嚴格大於該節點的值。左右子樹也必須是二叉查詢樹。一個節點的樹

搜尋排序

內容和程式碼參考殷人昆版的《資料結構》 二叉搜尋樹也稱為二叉排序樹,二叉搜尋樹要麼是空樹,要麼具有如下性質: (1)每個結點都有一個作為搜尋依據的結點值,並且每個結點值互不相同; (2)左子樹(如果存在)上的所有結點值都小於根結點的值; (3)右子樹(如果存在)上的所有結點

數據結構之

創建 int iter out for 結點 spa left nbsp 輸出二叉樹中所有從根結點到葉子結點的路徑 1 #include <iostream> 2 #include <vector> 3 us

新手算法學習之路----的路徑和

== style oid 添加 roo span 一個 int 二叉 題目: 給定一個二叉樹,找出所有路徑中各節點相加總和等於給定 目標值 的路徑。 一個有效的路徑,指的是從根節點到葉節點的路徑。 代碼加思路: public List<List<Intege

性質與存儲

tco img 分享圖片 pos 技術 master blog lee mar 二叉樹的性質及存儲如下 二叉樹(性質與存儲)