二叉查找树的原理与实现

二叉查找树,又名二叉搜索树,主要性质:左孩子 < 父 < 右孩子,如果将二叉查找树按前序遍历输出的话,输出的序列则是由小到大的有序序列。

二叉查找树上的基本操作包括:search, minimum, maximum, predecessor, successor, insert, delete. 而这些操作基本所花费的时与这棵树的高度成正比。对于一棵完全树来说,这些操作的最坏运行时间为:O(lgn),而对于n个结点连成一条线的树来说,则为O(n)。那如何才能保证所有的基本操作复杂度控制在O(lgn)呢? 这在下一节中,我将给二叉查找树的变形体------>红黑树,B树。

下面分别介绍二叉查找树的相关操作:

(1)search:

 树的高度为h, 时间复杂度为O(h).

Tree_Search(root, k)

while root !=NULL and k!=root.data
    if k >root.data
        root = root.rchild
    else
        root = root.lchild

return root


(2)Minimum:

很容易知道,一棵二叉查找树的最小元素是它的最左端的叶子结点。很容易可以写出它的算法:

Tree_Minimum(root)

while(root !=NULL)
   x = root
   root = root.lchild

return x


(3)Maximum:

同理,可以知道maximum的算法

Tree_Minimum(root)

while(root !=NULL)
   x = root
   root = root.rchild

return x


(4)Successor:

查找一个二叉树结点的后继,即查找大小紧跟其后的一个结点。

如果,该结点存在右子树,则直接返回其右子树的最小元素 。反之,按照“左上-->左上-->在上--......-->右上”的线路寻找。

Tree_Successor( x )

if x.right != NULL
   return Minimum(x.right)
y = x.p
while(y!=NULL and x = y.right)
   x = y
   y = y.p

return y


(5)Predecessor:

与Successor的实现对称。如果该结点存在左子树,则直接返回其左子树的最大元素。反之,按照“右上--》右上---》。。。右上--》左上"的线路寻找

Tree_Predecessor( x )

if x.left!= NULL
   return Maximun(x.left)
y = x.p
while(y!=NULL and x = y.left)
   x = y
   y = y.p

return y


(6)Insert:

while(x!=NUll)
   y = x
   if(k<x.data)
      x = x.left
   else 
      x = x.right
 z.p = y
 if y  = NULL
     root = z
 if k<y.data
    y.left = z
 else 
    y.right = z


(7)delete:

 分情况讨论:被删除的结点为z

 #1、如果z没有左孩子,则直接删除z, 用其右孩子来代替

 #2、如果z只有左孩子,直接删除z,用其左孩子来代替

 #3、如果z同时存在双孩子,则用查找y的后继,。。。。

其实可以这样简单地考虑,要被删除的结点为z, 而实际上被删除的结点为y(它的后继结点),而删除之前,互换z和y结点的值,指针不变。如果z同时存在左孩子和右孩子。

Tree_delete(x, z)

if z.left = NULL or z.right = NULL
	y = z
else 
	y = z.Successor()
if y.left != NULL
	x = y.left 
else 
	x = y.right
#删除y,则用x为根的子树去替换它即可
p.x = p.y
if p.y == NULL
	root = x
else if y = y.p.left 
	    y.p.left = x
    
     else 
	    y.p.right = x

if y != z   #如果y和z不是同一个结点,则交换二者的元素值
	z.data = y.data


二叉查找树的简单实现:

// 二叉查找树.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>

using namespace std;

typedef struct BITree
{
	int key;
	BITree *left;
	BITree *right;
	BITree *p;
}BITree;

BITree * Serach(BITree *root , int x)
{
	//用非递归的做法实现
	BITree *p = root;
	while(p!=NULL && x!=p->key)
	{
		if(x<p->key)
			p = p->left;
		else
			p = p->right;
	}
	return p;  //这时p可能为NULL,则说明没有查找到该关键字
}

BITree * SerachMin(BITree *root)
{
	BITree *p = root;
	while(p->left!=NULL)
	{
		p = p->left;
	}
	return p;

}

BITree * SerachMax(BITree *root)
{
	BITree *p = root;
	while(p->right!=NULL)
	{
		p = p->right;
	}
	return p;
}

//查找某结点的前驱
BITree *FindProcessor(BITree *Node)
{
	return NULL;
}

//查找某节点的后继,后继并非链表中所指,二叉树中的后继是关键字比它大的最小元素
//如果该结点的右子树非空,则直接返回右子树的最小结点
//如果该结点的右子树为空,则其后继为带有左孩子的最底层结点
BITree *FindSuccessor(BITree *Node)
{
	if(Node->right!=NULL)
		return SerachMin(Node->right);
	BITree *p = Node->p;
	while(p!=NULL && Node == p->right)
	{
		Node = p;
		p = p->p;
	}
	return p;

}

//
void insert(BITree *&root, int x)
{
	BITree *p = root;
	BITree *y = NULL;
	BITree *insertNode = new BITree;
	insertNode->key = x;
	insertNode->left = NULL;
	insertNode->right = NULL;
	while(p!=NULL)
	{
		y = p;
		if(x<p->key)
			p = p->left;
		else
			p = p->right;
	}
	insertNode->p = y;
	if(y == NULL) //即这是一棵空子树
		root = insertNode;
	else if(x<y->key)
		y->left = insertNode;
	else
		y->right = insertNode;
}

void TransParent(BITree *root, BITree *p, BITree *q)
{
	if(p->p == NULL) //p结点是root,那么直接将q置为root
		root = q;
	else if(p == p->p->left)
		p->p->left = q;
	else
		p->p->right = q;
	if(q!=NULL)
		q->p = p->p;


}
//Delete:有4种情况,令要删除的结点为pNode;
//1、pNode没有左孩子,那么直接用其右孩子代替它
//2、pNode只有左孩子,直接用左孩子代替它
//3、pNode既有左孩子,又有右孩子。那么查找它的后继,该结点是没有左孩子的。那么还应考虑该后继是它的右结点还只是右子树中的某个结点。
void deleteNode(BITree *&root,int x) //这里传二级指针是因为:删除结点可能改变root
{
	BITree * p = Serach(root,x);
	cout<<"Delete Node key:"<<p->key<<endl;
	if(p->left == NULL)
		TransParent(root,p,p->right);
	else if(p->right == NULL)
		TransParent(root,p,p->left);
	else
	{
		BITree *k = SerachMin(p->right);
		cout<<"Min Key"<<k->key<<endl;
		if(k != p->right)//如果该后继结点刚好是p的右孩子,那么将k替换p,此时p的左孩子成为k的左孩子,该左孩子的父亲即为k.
		{
			TransParent(root,k,k->right);
			k->right = p->right;
			k->right->p = k;
		}//如果该后 继结点不是p的右孩子,那么将k的右孩子转化为k,并成为其双亲的一个孩子。然后将p的右孩子变为y的右孩子。
		TransParent(root,p,k);
		k->left = p->left;
		k->left->p = k;
	}
}

/*void Create(BITree *root)
{
	int key;
	cout<<"input the node:";
	cin>>key;
	while(key!=0)
	{
		insert(root,key);
	}

}*/

void Create(int nodeArray[], int length, BITree *&root)
{
	int i;
	for(i = 0;i<length;i++)
	{
		insert(root,nodeArray[i]);
	}
}

void printInorder(BITree *root)
{
	BITree *p = root;
	if(p!=NULL)
	{
		printInorder(p->left);
		cout<<p->key<<' ';
		printInorder(p->right);
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	int i;
	BITree *root =NULL;
	int nodeArray[11] = {15,6,18,3,7,17,20,2,4,13,9};
	Create(nodeArray,11,root);
	printInorder(root);
	deleteNode(root,15);
	printInorder(root);
	return 0;
}


二叉查找树的类模板实现 :

// 二叉查找树类模板实现.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <stack>

using namespace  std;

template<class T>
struct _TreeNode
{
	T data;
	struct _TreeNode *p;
	struct _TreeNode *left;
	struct _TreeNode *right;
};


template<class T>
class SearchTree
{
private:
	typedef struct _TreeNode<T> TreeNode, *pTreeNode;
	TreeNode *root;

public:
	SearchTree();
	~SearchTree();

	void createSearchTree(T *s , int length);
	TreeNode * Minimum(TreeNode *pNode) const;
	TreeNode * Maximum(TreeNode *pNode) const;
	TreeNode * Search(T k);
	TreeNode * Successor(TreeNode *pNode) const;
	TreeNode * Predessor(TreeNode *pNode) const;
	TreeNode * _allocNode();
	void Insert_Node(TreeNode *pNode);
	void delete_Node(T k);
	void _printInOrder() const;

};


template<class T>
SearchTree<T>::SearchTree()
{
	root = _allocNode();
}

template<class T>
SearchTree<T>::~SearchTree()
{
	delete root;
	root = NULL;
}

template<class T>
typename SearchTree<T>::TreeNode * SearchTree<T>::_allocNode()
{
	TreeNode *newNode = new TreeNode;
	newNode->data = NULL;
	newNode->left = NULL;
	newNode->right = NULL;
	newNode->p = NULL;
	return newNode;
}

template<class T>
typename SearchTree<T>::TreeNode *SearchTree<T>::Search(T k)
{
	TreeNode *searchNode = root;
	while(searchNode!=NULL && k!=searchNode->data)
	{
		if(k<searchNode->data)
			searchNode = searchNode->left;
		else 
			searchNode = searchNode->right;
	}
	return searchNode;
}
//pNode表示寻找以它为根的子树的最小值
template<class T>
typename SearchTree<T>::TreeNode * SearchTree<T>::Minimum(TreeNode *pNode) const
{
	while(pNode->left )
	{
		pNode = pNode->left;
	}
	return pNode;
}

//pNode表示寻找以它为根的子树的最大值
template<class T>
typename SearchTree<T>::TreeNode * SearchTree<T>::Maximum(TreeNode *pNode) const
{
	while(pNode->right )
	{
		pNode = pNode->right
	}
	return pNode;
}

template<class T>
typename SearchTree<T>::TreeNode * SearchTree<T>::Successor(TreeNode *pNode) const
{
	if(pNode->right)
		return Minimum(pNode->right);
	TreeNode *y = pNode->p;
	while(y!=NULL && pNode == y->right)
	{
		pNode = y;
		y = y->p;
	}
	return y;
}

template<class T>
typename SearchTree<T>::TreeNode * SearchTree<T>::Predessor(TreeNode *pNode) const
{
	if(pNode->left)
		return Minimum(pNode->left);
	TreeNode *y = pNode->p;
	while(y!=NULL && pNode == y->left)
	{
		pNode = y;
		y = y->p;
	}
	return y;
}

template<class T>
void SearchTree<T>::Insert_Node(typename SearchTree<T>::TreeNode *insertNode)
{
	typename SearchTree<T>::TreeNode *x = root;
	typename SearchTree<T>::TreeNode *temp = NULL;
	while(x)
	{
		temp = x;
		if(insertNode->data < x->data)
			x = x->left;
		else
			x  = x->right;
	}
	insertNode->p = temp;
	if(!temp)
		root = insertNode;
	else if(insertNode->data<temp->data)
		temp->left = insertNode;
	else 
		temp->right = insertNode;
}
//用TNULL取代NULL,可以使用程序更加简洁
template<class T>
void SearchTree<T>::delete_Node(T k)
{
	typename SearchTree<T>::TreeNode *deleteNode = Search(k);
	typename SearchTree<T>::TreeNode *y = NULL;
	typename SearchTree<T>::TreeNode *x = NULL;
	if(deleteNode->left == NULL || deleteNode->right == NULL)
	{
		y = deleteNode;
	}
	else
		y = Successor(deleteNode);

	if(deleteNode!=y)
		deleteNode->data = y->data;	

	if(!y->left)
		x = y->left;
	else
		x = y->right;
	if(x != NULL)
	{
		x->p = y->p;
		if(y->p == NULL)
			root = x;
		else if(y = y->p->left)
			y->p->left = x;
		else
			y->p->right = x;
	}
	else
	{
		if(y = y->p->left )
			y->p->left = NULL;
		else
			y->p->right = NULL;
		delete y;
		y = NULL;
	}
}

//创建二叉树就是不断地插入新结点的过程
template<class T>
void SearchTree<T>::createSearchTree(T *s,int lenght) 
{
	root->data = s[0];
	for(int i = 1;i<lenght;i++)
	{
		typename SearchTree<T>::TreeNode *newNode = _allocNode();
		newNode->data = s[i];
		Insert_Node(newNode);
	}
}

/*template<class T>
void SearchTree<T>::printInorder(typename SearchTree<T>::TreeNode *pRoot) const
{
	if(pRoot!=NULL)
	{
		printInorder(pRoot->lchild);
		cout<<pRoot->data<<',';
		printInorder(pRoot->rchild);

	}
}*/

//中序非递归遍历
template<class T>
void SearchTree<T>::_printInOrder() const
{
	typedef struct _TreeNode<T> TreeNode;
	stack<TreeNode *> s;
	TreeNode *p = root;
	while(!s.empty() ||p!=NULL)
	{
		while(p!=NULL)
		{
			s.push(p);
			p = p->left;
		}

		if(!s.empty())
		{
			TreeNode *temp = s.top();
			s.pop();
			cout<<temp->data<<',';
			p = temp->right;
		}
	}
}


int _tmain(int argc, _TCHAR* argv[])
{
	SearchTree<int> *tree = new SearchTree<int>;
	int s[] = {15,2,4,3,7,6,18,17,20,13,9};
	tree->createSearchTree(s,11);
	tree->_printInOrder();
	cout<<endl<<"delete 15:"<<endl;
	tree->delete_Node(s[0]);
	tree->_printInOrder();
	return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值