二叉搜索树的查找

---------------------siwuxie095

二叉搜索树的查找

程序:二叉搜索树和顺序查找表的查找对比

FileOps.h:


#ifndef FILEOPS_H

#define FILEOPS_H

#include <string>

#include <iostream>

#include <fstream>

#include <vector>

using namespace std;

namespace FileOps

{

int firstCharacterIndex(const string &s, int start)

{

for (int i = start; i < s.length(); i++)

{

if (isalpha(s[i]))

{

return i;

}

}

return s.length();

}

//把大写字符串转换为小写字符串

string lowerS(const string &s)

{

string ret = "";

for (int i = 0; i < s.length(); i++)

{

ret += tolower(s[i]);

}

return ret;

}

//将文件读入words数组中

bool readFile(const string& filename, vector<string> &words)

{

string line;

string contents = "";

ifstream file(filename);

if (file.is_open())

{

while (getline(file, line))

{

contents += (line + "\n");

}

file.close();

}

else

{

cout << "Can not open " << filename << " !!!" << endl;

return false;

}

int start = firstCharacterIndex(contents, 0);

for (int i = start + 1; i <= contents.length();)

{

if (i == contents.length() || !isalpha(contents[i]))

{

words.push_back(lowerS(contents.substr(start, i - start)));

start = firstCharacterIndex(contents, i);

i = start + 1;

}

else

{

i++;

}

}

return true;

}

}

#endif

BST.h:


#ifndef BST_H

#define BST_H

#include
"stdlib.h"

#include <queue>

//二叉搜索树

template <typename Key, typename Value>

class BST

{

private:

struct Node

{

Key key;

Value value;

Node *left;

Node *right;

Node(Key key, Value value)

{

this->key = key;

this->value = value;

this->left = this->right = NULL;

}

Node(Node *node)

{

this->key = node->key;

this->value = node->value;

this->left = node->left;

this->right = node->right;

}

};

Node *root; //根节点

int count;

public:

BST()

{

root = NULL;

count = 0;

}

~BST()

{

destroy(root);

}

int size()

{

return count;

}

bool isEmpty()

{

return count == 0;

}

//向整棵二叉树树中插入新元素转换成向一个子树中插入新元素

//直到子树是空的时候,新建一个节点,这个新建的节点就是一

//棵新的子树,只不过它只有一个节点,将它直接返回回去

//

//这样,通过递归的方式向二叉搜索树中插入了一个新的元素

void insert(Key key, Value value)

{

root = insert(root, key, value);

}

bool contain(Key key)

{

return contain(root, key);

}

//search()函数常见的返回形式:

//(1)Node*,缺点:对外界来说,没有将数据结构Node进行隐藏

//(2)Value,缺点:如果查找不到的话,不知道该返回什么数值

//(3)Value*,优点:作为一个指针可以存一个空元素

Value *search(Key key)

{

return search(root, key);

}

// 前序遍历

void preOrder()

{

preOrder(root);

}

// 中序遍历:会将二叉搜索树的key从小到大进行排序

void inOrder()

{

inOrder(root);

}

// 后序遍历

void postOrder()

{

postOrder(root);

}

// 层序遍历

void levelOrder()

{

//需要引入队列:先进先出

queue<Node*> q;

q.push(root);

while (!q.empty())

{

Node *node = q.front();

q.pop();

cout << node->key << endl;

//如果node的左孩子不为空

if (node->left)

{

q.push(node->left);

}

//如果node的右孩子不为空

if (node->right)

{

q.push(node->right);

}

}

}

// 寻找最小的键值

Key minimum()

{

assert(count != 0);

Node *minNode = minimum(root);

return minNode->key;

}

// 寻找最大的键值

Key maximum()

{

assert(count != 0);

Node *maxNode = maximum(root);

return maxNode->key;

}

// 从二叉树中删除最小值所在节点

void removeMin()

{

//根节点不为空,才能做事情

if (root)

{

root = removeMin(root);

}

}

// 从二叉树中删除最大值所在节点

void removeMax()

{

if (root)

{

root = removeMax(root);

}

}

// 从二叉树中删除键值为key的节点

void remove(Key key)

{

root = remove(root, key);

}

private:

// 向以node为根的二叉搜索树中,插入节点(key, value)

// 返回插入新节点后的二叉搜索树的根

Node *insert(Node *node, Key key, Value value)

{

//递归到底的情况:如果一个节点都没有,

//创建一个新节点作为子树的根

if (node == NULL)

{

count++;

return new Node(key, value);

}

//如果新插入节点的key等于当前节点的key,做更新操作即可

if (key == node->key)

{

node->value = value;

}

else if (key < node->key)

{

node->left = insert(node->left, key, value);

}

else

{

// key > node->key

node->right = insert(node->right, key, value);

}

return node;

}

// 查看以node为根的二叉搜索树中是否包含键值为key的节点

bool contain(Node *node, Key key)

{

//如果当前访问的节点已经为空,

//即不包含,直接返回false即可

if (node == NULL)

{

return false;

}

if (key == node->key)

{

return true;

}

else if (key < node->key)

{

return contain(node->left, key);

}

else

{

// key > node->key

return contain(node->right, key);

}

}

// 在以node为根的二叉搜索树中查找key所对应的value

Value *search(Node *node, Key key)

{

if (node == NULL)

{

return NULL;

}

if (key == node->key)

{

return &(node->value);

}

else if (key < node->key)

{

return search(node->left, key);

}

else

{

// key > node->key

return search(node->right, key);

}

}

// 对以node为根的二叉搜索树进行前序遍历

void preOrder(Node *node)

{

if (node != NULL)

{

cout << node->key << endl;

preOrder(node->left);

preOrder(node->right);

}

}

// 对以node为根的二叉搜索树进行中序遍历

void inOrder(Node *node)

{

if (node != NULL)

{

inOrder(node->left);

cout << node->key << endl;

inOrder(node->right);

}

}

// 对以node为根的二叉搜索树进行后序遍历

void postOrder(Node *node)

{

if (node != NULL)

{

postOrder(node->left);

postOrder(node->right);

cout << node->key << endl;

}

}

void destroy(Node *node)

{

//使用后序操作的方式来释放整棵树

if (node != NULL)

{

destroy(node->left);

destroy(node->right);

delete node;

count--;

}

}

// 在以node为根的二叉搜索树中,返回最小键值的节点

Node *minimum(Node *node)

{

if (node->left == NULL)

{

return node;

}

return minimum(node->left);

}

// 在以node为根的二叉搜索树中,返回最大键值的节点

Node *maximum(Node *node)

{

if (node->right == NULL)

{

return node;

}

return maximum(node->right);

}

// 删除掉以node为根的二叉搜索树中的最小节点

// 返回删除节点后新的二叉搜索树的根

Node *removeMin(Node *node)

{

//如果当前节点的左孩子为空,则当前节点为最小节点

//显然,最小值所在的节点只可能有右孩子

if (node->left == NULL)

{

Node *rightNode = node->right;

delete node;

count--;

return rightNode;

}

node->left = removeMin(node->left);

return node;

}

// 删除掉以node为根的二叉搜索树中的最大节点

// 返回删除节点后新的二叉搜索树的根

Node* removeMax(Node* node)

{

//如果当前节点的右孩子为空,则当前节点为最大节点

//显然,最大值所在的节点只可能有左孩子

if (node->right == NULL)

{

Node *leftNode = node->left;

delete node;

count--;

return leftNode;

}

node->right = removeMax(node->right);

return node;

}

// 删除掉以node为根的二叉搜索树中键值为key的节点

// 返回删除节点后新的二叉搜索树的根

Node* remove(Node* node, Key key)

{

if (node == NULL)

{

return NULL;

}

if (key < node->key)

{

node->left = remove(node->left, key);

return node;

}

else if (key > node->key)

{

node->right = remove(node->right, key);

return node;

}

else

{ // key == node->key

//如果node只有右孩子

if (node->left == NULL)

{

Node *rightNode = node->right;

delete node;

count--;

return rightNode;

}

//如果node只有左孩子

if (node->right == NULL)

{

Node *leftNode = node->left;

delete node;

count--;

return leftNode;

}

// node->left != NULL && node->right != NULL

//即node的左右孩子都不为空

Node *successor = new Node(minimum(node->right));

count++;

successor->right = removeMin(node->right);

successor->left = node->left;

delete node;

count--;

return successor;

}

}

};

//前中后序遍历属于深度优先遍历

//而层序遍历则属于广度优先遍历

//

//这四种遍历方式相对都非常高效,时间复杂度是O(n)

//

//

//

//二叉搜索树中,最复杂的一个操作就是删除节点

//

//其实删除一个节点很容易,关键是将这个节点删除之后,如何来处理

//与这个节点相关联的部分,使得整棵树依然保持二叉搜索树的性质

//

//

//如果要删除的节点只有一个孩子,那么这个问题很简单,和删除最大

//(小)值所在节点的方法一样,最难的是删除左右都有孩子的节点

//

//处理这种情况的一个非常经典的算法就是Hibbard Deletion,这个算

//法在 1962 年被一个叫做 Hibbard 的计算机科学家提出,具体如下:

//

//假如这个被删除的节点是 d,d 既有左孩子,又有右孩子,其实要做

//的事情就是找一个节点来代替 d,这个节点既不应该是 d 的左孩子,

//也不应该是 d 的右孩子,Hibbard 提出这个节点应该是 d 的右子树

//中的最小值

//

//删除左右都有孩子的节点 d,用 s 来代替,即 s 是 d 的后继

//(d 即 deletion,s 即 successor)

//

//s=min(d->right)

//s->right=delMin(d->right)

//s->left=d->left

//

//删除 d,s 是新的子树的根

//

//

//

//其实代替的节点也可以是 d 的左子树中的最大值,如下:

//

//删除左右都有孩子的节点 d,用 p 来代替,p 是 d 的前驱

//(d 即 deletion,p 即 predecessor)

//

//p=max(d-left)

//p->left=delMax(d->left)

//p->right=d->right

//

//删除 d,p 是新的子树的根

//

//

//删除二叉搜索树中的任意一个节点
时间复杂度 O(lgn)

#endif

SequenceST.h:


#ifndef SEQUENCEST_H

#define SEQUENCEST_H

#include <iostream>

#include <cassert>

using namespace std;

//顺序查找表:采用链表的数据结构实现

template<typename Key, typename Value>

class SequenceST

{

private:

struct Node

{

Key key;

Value value;

Node *next;

Node(Key key, Value value)

{

this->key = key;

this->value = value;

this->next = NULL;

}

};

Node* head;

int count;

public:

SequenceST()

{

head = NULL;

count = 0;

}

~SequenceST()

{

while (head != NULL)

{

Node *node = head;

head = head->next;

delete node;

count--;

}

assert(head == NULL && count == 0);

}

int size()

{

return count;

}

bool isEmpty()

{

return count == 0;

}

void insert(Key key, Value value)

{

Node *node = head;

while (node != NULL)

{

if (key == node->key)

{

node->value = value;

return;

}

node = node->next;

}

Node *newNode = new Node(key, value);

newNode->next = head;

head = newNode;

count++;

}

bool contain(Key key)

{

Node *node = head;

while (node != NULL)

{

if (key == node->key)

{

return true;

}

node = node->next;

}

return false;

}

Value* search(Key key)

{

Node *node = head;

while (node != NULL)

{

if (key == node->key)

{

return &(node->value);

}

node = node->next;

}

return NULL;

}

void remove(Key key)

{

if (key == head->key)

{

Node* delNode = head;

head = head->next;

delete delNode;

count--;

return;

}

Node *node = head;

while (node->next != NULL && node->next->key != key)

{

node = node->next;

}

if (node->next != NULL)

{

Node* delNode = node->next;

node->next = delNode->next;

delete delNode;

count--;

return;

}

}

};

#endif

main.cpp:


#include
"FileOps.h"

#include
"BST.h"

#include
"SequenceST.h"

#include <iostream>

#include <vector>

#include <string>

#include <ctime>

using namespace std;

int main()

{

//把英文版圣经作为测试用例

string filename = "bible.txt";

vector<string> words;

//readFile()可以将bible.txt中的所有单词存进words数组中

if (FileOps::readFile(filename, words))

{

cout << "There are totally " << words.size() << " words in " << filename << endl;

cout << endl;

// test BST:

//

//从头到尾的访问在圣经中出现的每一个单词

//每一个单词作为 key,计算它的词频(每一个单词出现的频次)作为 value

//

time_t startTime = clock();

BST<string, int> bst = BST<string, int>();

//将单词作为key放在迭代器iter中

for (vector<string>::iterator iter = words.begin(); iter != words.end(); iter++)

{

//对当前单词进行search操作

int *res = bst.search(*iter);

//如果为空,则词频为1,否则做++操作

if (res == NULL)

{

bst.insert(*iter, 1);

}

else

{

(*res)++;

}

}

//查找操作:单词 god 的词频

cout << "‘god‘ : " << *bst.search("god") << endl;

time_t endTime = clock();

cout << "BST , time: " << double(endTime - startTime) / CLOCKS_PER_SEC

<< " s." << endl;

cout << endl;

// test SST:

//

//为了对比二叉搜索树的效率,实现了一个顺序查找表 SequenceST

//

//结果:二叉搜索树确实在时间性能效率上比顺序查找法高出了一个量级

//

startTime = clock();

SequenceST<string, int> sst = SequenceST<string, int>();

for (vector<string>::iterator iter = words.begin(); iter != words.end(); iter++)

{

int *res = sst.search(*iter);

if (res == NULL)

{

sst.insert(*iter, 1);

}

else

{

(*res)++;

}

}

cout << "‘god‘ : " << *sst.search("god") << endl;

endTime = clock();

cout << "SST , time: " << double(endTime - startTime) / CLOCKS_PER_SEC

<< " s." << endl;

}

system("pause");

return
0;

}

【made by siwuxie095】

时间: 2024-10-31 21:20:56

二叉搜索树的查找的相关文章

二叉搜索树的查找与删除

在二叉搜索树中查找一个数,如果存在,则从树中删除. struct Node { Node* left; Node* right; int data; }; void findAndDel(Node*& head, int k) { if (!head) return; Node* node = head; Node* vnode = new Node; vnode->left = vnode->right = head; Node* pnode = vnode; // find nod

【数据结构】第9章 查找! (二叉搜索树BST AVL树 B-(+)树 字典树 HASH表)

难产的笔记...本来打算用1天 结果前前后后拖了5天 §9.1 静态查找表 9.1.1 顺序表的查找 各种扫 自己脑补吧 复杂度O(n) 9.1.2 有序表的查找 若表是单调的,则可以利用二分查找.复杂度O(logn) 9.1.3 静态树表的查找 见 http://blog.csdn.net/area_52/article/details/43795837 9.1.4 索引顺序表的查找 建立索引表查找 §9.2 动态查找表 动态查找表的特点是,表结构本身是在查找过程中动态生成的,即对于给定值ke

数据结构(六)查找---二叉搜索树(排序树)

前提 前面的查找我们都是静态查找,因为数据集是有序存放,查找的方法有多种,可以使用折半,插值,斐波那契等,但是因为有序,在插入和删除操作上的效率并不高. 这时我们就需要一种动态查找方法,既可以高效实现查找,又可以使得插入和删除效率不错,这时我们可以考虑二叉排序树 二叉排序树 一:定义 又称为二叉搜索树(查找树),是一棵树,可以为空,但是需要满足以下性质: 1.非空左子树的所有键值小于其根节点的键值 2.非空右子树的所有键值大于其根节点的键值 3.左右子树都是二叉搜索树 二:操作 查找 /* Bi

数据结构第三部分:树与树的表示、二叉树及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树、集合及其运算

参考:浙大数据结构(陈越.何钦铭)课件 1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找——方法一:顺序查找(时间复杂度O(n)) int

二叉搜索树的局限性

-------------------siwuxie095 二叉搜索树的局限性 二叉搜索树在时间性能上是具有局限性的 同样的数据,可以对应不同的二叉搜索树,如下: 二叉搜索树可能退化成链表,相应的,二叉搜索树的查找操作是和这棵树 的高度相关的,而此时这颗树的高度就是这颗树的节点数 n,同时二叉搜 索树相应的算法全部退化成 O(n) 级别 显然,说二叉搜索树的查找.插入.删除 这三个操作都是 O(lgn) 级别的, 只是一个大概的估算,具体要和二叉搜索树的形状相关 二叉搜索树并不能像堆那样,保证所

数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉搜索树.红黑树.线索二叉树,它们在解决实际问题中有着非常重要的应用.本文主要从概念和一些基本操作上进行分类和总结. 一.概念总揽 (1) 堆 堆(heap order)是一种特殊的表,如果将它看做是一颗完全二叉树的层次序列,那么它具有如下的性质:每个节点的值都不大于其孩子的值,或每个节点的值都不小于其孩子的值

数据结构 ---- 二叉搜索树

一直对于二叉搜索树(又叫二叉排序树,也叫二叉查找树),没有很好的理解,决定花点时间来学习and总结.. 二叉搜索树也是二叉树的一种.(就像堆也就二叉树的一种一样...) 只不过,二叉搜索树也是有其他要求:对于所有的子树,其根节点的值大于左子树上的所有结点的值,而小于右子树上所有结点的值的值.. 对于错误的理解:对于所有的结点,要大于其左结点,小于其右结点..(PS:这种理解是错误的,一定要注意..) 还有一点需要注意的是:我们的大于和小于都应该是严格的. ========== 下面主要针对,其建

二叉搜索树递归算法

二叉搜索树的查找——递归算法: bool Find(BTreeNode* BST,ElemType& item)  { if (BST==NULL)       return false; //查找失败 else {          if (item==BST->data){ item=BST->data;//查找成功 return  ____true_______;} else if(item<BST->data) eturn  Find(____BST->lef

数据结构学习笔记04树(二叉树、二叉搜索树、平衡二叉树)

一.树 树的基本术语 ①结点的度(Degree):结点的子树个数 ②树的度:树的所有结点中最大的度数 ③叶结点(Leaf):度为0的结点 ④父结点(Parent):有子树的结点是其子树的根结点的父结点 ⑤子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点:子结点也称孩子结点. ⑥兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点. ⑦路径和路径长度:从结点n1到nk的路径为一个结点序列n1 , n2 ,… , nk , ni是 ni+1的父结点.路径所包含边