二叉查找树的基类实现(下)
来源:互联网 发布:lr推荐算法 编辑:程序博客网 时间:2024/06/05 13:30
二叉查找树的基类实现(五)
下面是树的实现,它的数据域只需要一个根节点
完成的主要工作是插入,删除和查找
BSTree.h 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//此类是二叉搜索树类的定义部分
#include "BinaryTreeNode.h"
class
BSTree
{
private
:
//根节点
BinaryTreeNode *root;
public
:
BSTree();
public
:
BinaryTreeNode *get(ObjectClass *theKey);
//搜索
BinaryTreeNode *getRoot();
//返回根节点
BinaryTreeNode *
remove
(ObjectClass *theKey);
//删除
void
insert(ObjectClass *theKey, ObjectClass *theValue);
//插入
void
ascend(BinaryTreeNode *);
//遍历
int
calWidth(BinaryTreeNode *);
//计算各节点的长度
void
outPut();
//输出
BinaryTreeNode *tree_minimum(BinaryTreeNode *p);
//最小节点
BinaryTreeNode *tree_maximum(BinaryTreeNode *p);
//最大节点
BinaryTreeNode *tree_successor(BinaryTreeNode *p);
//后继节点
};
BSTree.cpp 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
//此文件是二叉搜索树的实现部分
#include "BSTree.h"
#include <iostream>
#include "queue.h"
using
namespace
std;
BSTree::BSTree()
{
root = NULL;
//根节点默认为NULL
}
//查找关键字为theKey的节点并返回指向节点的指针,找不到则返回空指针
BinaryTreeNode *BSTree::get(ObjectClass *theKey)
{
BinaryTreeNode *p=root;
while
(p!=NULL)
{
//if(theKey < p->getKey())
if
(theKey->Compare(p->getKey()) == -1)
p=p->getLeft();
//if(theKey > p->getKey())
else
if
(theKey->Compare(p->getKey()) == 1)
p=p->getRight();
else
//如果找到了相同的关键字则成功返回
return
p;
}
return
NULL;
}
//插入一个节点,如果节点关键字已经存在则覆盖,否则插入到叶子节点处
void
BSTree::insert(ObjectClass *theKey,ObjectClass *theValue)
{
BinaryTreeNode *p=root;
//search pointer
BinaryTreeNode *parent=NULL;
//parent of p;
while
(p!=NULL)
{
parent=p;
//if(theKey < p->getKey())
if
(theKey->Compare(p->getKey()) == -1)
p=p->getLeft();
//if(theKey > p->getKey())
else
if
(theKey->Compare(p->getKey()) == 1)
p=p->getRight();
else
{
p->setValue(theValue);
//如果找到相同的关键字则覆盖原有的
return
;
}
}
//等待插入的新节点
BinaryTreeNode *newNode =
new
BinaryTreeNode(theKey,theValue);
if
(root == NULL)
root = newNode;
else
{
//当p为空的时候parent最多只有一个儿子节点
//if(theKey < parent->getKey())
if
(theKey->Compare(parent->getKey()) == -1)
{
parent->setLeft(newNode);
newNode->setParent(parent);
}
else
{
parent->setRight(newNode);
newNode->setParent(parent);
}
}
return
;
}
//删除节点,如果这个节点含有少于两个儿子节点,则直接删除它,然后将它的儿子节点链接到它原来所在的位置
//如果这个节点含有两个儿子节点,则要先删除它的后继节点,然后将它的后继节点的值换给它
BinaryTreeNode *BSTree::
remove
(ObjectClass *theKey)
{
//先查找到要删除的节点指针
BinaryTreeNode *deletedNode=get(theKey);
if
(deletedNode==NULL)
return
NULL;
//即将被删除的节点,注意这个节点最多只含有一个儿子节点
BinaryTreeNode *todelete;
//被删除节点的儿子节点
BinaryTreeNode *nextNode;
if
(deletedNode->getLeft()==NULL || deletedNode->getRight()==NULL)
//当要删除的节点只含有最多一个儿子节点时则即将被删除节点就是要删除的节点
todelete = deletedNode;
else
todelete = tree_successor(deletedNode);
//否则的话删除它的后继节点
//获取唯一的儿子节点,准备当前即将删除节点的删除工作
if
(todelete->getLeft()!=NULL)
nextNode=todelete->getLeft();
else
nextNode=todelete->getRight();
//开始删除节点
if
(nextNode!=NULL)
nextNode->setParent(todelete->getParent());
if
(todelete->getParent()==NULL)
nextNode=root;
else
if
(todelete->getParent()->getLeft()==todelete)
todelete->getParent()->setLeft(nextNode);
else
todelete->getParent()->setRight(nextNode);
//节点成功删除,删完后在考虑将原来节点的后续节点值的替换
if
(todelete!=deletedNode)
{
deletedNode->setKey(todelete->getKey());
deletedNode->setValue(todelete->getValue());
}
//返回被删除的节点
return
todelete;
}
//计算左右的宽度,使用递归算法
int
BSTree::calWidth(BinaryTreeNode *p)
{
if
(p!=NULL)
{
int
leftWidth=0;
//左宽度
int
rightWidth=0;
//右宽度
if
(p->getLeft()!=NULL)
leftWidth=calWidth(p->getLeft())+p->getKey()->getLength();
//左宽度是左子树的总宽度加上本节点的长度
if
(p->getRight()!=NULL)
rightWidth=calWidth(p->getRight())+p->getKey()->getLength();
//右宽度是右子树的总宽度加上本节点的长度
p->setWidth(leftWidth,rightWidth);
//设置左右宽度
//返回本节点为根的子树总宽度
return
leftWidth+rightWidth;
}
}
//按照层次遍历子树并且打印出来
void
BSTree::ascend(BinaryTreeNode *p)
{
calWidth(p);
//计算左右子树的宽度
p->setLeftOutPutLen(p->getLeftWidth());
//设置最顶层的左边预留宽度
//下面要用队列实现树的层次遍历
Queue<BinaryTreeNode *> Q;
Q.EnQueue(p);
int
number=0;
//存储下一层的元素个数
int
numberLeave=1;
//这一层还剩下多少元素
BinaryTreeNode *dep;
//保存当前从队列弹出的节点指针
int
preLeftWidth=0;
//存储前一个节点的左宽度,以便后面一个节点的打印
//如果当前节点在最开始,则前一节点左宽度为0
bool
firstIn=
true
;
while
(!Q.isEmpty())
//打印所有节点
{
dep=Q.DeQueue();
numberLeave--;
if
(dep!=NULL)
{
if
(dep->getLeft()!=NULL)
{
Q.EnQueue(dep->getLeft());
//左节点加入队列
number++;
//下层节点加一
}
if
(dep->getRight()!=NULL)
{
Q.EnQueue(dep->getRight());
//右节点加入队列
number++;
//下层节点加一
}
int
leftOutPutLen=dep->getLeftWidth();
//如果是第一次进入就左边预留宽度就是当前节点自己的宽度
if
(!firstIn)
{
if
(dep==dep->getParent()->getLeft())
leftOutPutLen = dep->getParent()->getLeftOutPutLen()-dep->getRightWidth()-dep->getParent()->getKey()->getLength();
//如果当前节点是左儿子,则它的左预留宽度是父节点的预留宽度减去当前节点右宽度
else
leftOutPutLen = dep->getParent()->getLeftOutPutLen()+dep->getLeftWidth()+dep->getParent()->getKey()->getLength();
//如果当前节点是右儿子,则它的左预留宽度是父节点的预留宽度加上当前节点的左宽度
dep->setLeftOutPutLen(leftOutPutLen);
//设置预留宽度
}
//根据当前节点左预留宽度和上一兄弟节点的结束宽度打印预留空格
for
(
int
i=0;i<leftOutPutLen-preLeftWidth;i++)
cout<<
" "
;
dep->getKey()->OutPut();
//打印当前节点
preLeftWidth=leftOutPutLen+dep->getKey()->getLength();
//计算当前节点的结束宽度,以便下一兄弟节点的打印
//如果当前节点在没有兄弟节点了就换行
if
(numberLeave == 0)
{
cout<<endl;
preLeftWidth=0;
numberLeave = number;
number = 0;
}
}
firstIn=
false
;
}
}
//输出,这里是默认从根节点输出,如果直接调用ascend则可以输出任何子树
void
BSTree::outPut()
{
BinaryTreeNode *temp=root;
ascend(temp);
}
BinaryTreeNode *BSTree::tree_minimum(BinaryTreeNode *p)
{
if
(p==NULL)
return
NULL;
BinaryTreeNode *pp=p;
while
(pp->getLeft()!=NULL)
pp=pp->getLeft();
return
pp;
}
BinaryTreeNode *BSTree::tree_maximum(BinaryTreeNode *p)
{
if
(p==NULL)
return
NULL;
BinaryTreeNode *pp=p;
while
(pp->getRight()!=NULL)
pp=pp->getRight();
return
pp;
}
//返回已知节点的后续节点
//如果这个节点有右子数,则返回右子树的最小节点
//否则向父节点寻找,找到第一个向右转的父节点为止
BinaryTreeNode *BSTree::tree_successor(BinaryTreeNode *p)
{
if
(p==NULL)
return
NULL;
BinaryTreeNode *pp=p;
if
(pp->getRight()!=NULL)
return
tree_minimum(pp->getRight());
BinaryTreeNode *y=p->getParent();
while
(y!=NULL && pp==y->getRight())
{
pp=y;
y=y->getParent();
}
return
y;
}
BinaryTreeNode *BSTree::getRoot()
{
return
root;
}
二叉查找树的基类实现(终)
下面举一个具体使用这个数据结构的例子,由于前面的缺点,这里
显得比较麻烦,也比较耗资源,但确实使用到了多态的好处
main.cpp 文件
#include <iostream>
#include "BSTree.h"
#include "IntClass.h"
#include "StringClass.h"
using
namespace
std;
int
main()
{
BSTree bstree;
BSTree bstreeStr;
bstree.insert(
new
IntClass(10),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(5),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(15),
new
StringClass(
"Lily"
,4));
bstree.insert(
new
IntClass(3),
new
StringClass(
"Tom"
,3));
bstree.insert(
new
IntClass(7),
new
StringClass(
"John"
,4));
bstree.insert(
new
IntClass(13),
new
StringClass(
"Peter"
,5));
bstree.insert(
new
IntClass(17),
new
StringClass(
"Joson"
,5));
bstree.insert(
new
IntClass(2),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(4),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(6),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(8),
new
StringClass(
"Lucy"
,4));
bstree.insert(
new
IntClass(11),
new
StringClass(
"Jim"
,3));
bstree.insert(
new
IntClass(14),
new
StringClass(
"Brown"
,5));
bstree.insert(
new
IntClass(16),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(18),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(1),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(9),
new
StringClass(
"Tao"
,3));
bstree.insert(
new
IntClass(12),
new
StringClass(
"Tao"
,3));
cout<<
"-------------------------------------------------"
<<endl;
cout<<
"The total tree is like this:"
<<endl;
bstree.outPut();
cout<<
"-------------------------------------------------"
<<endl;
cout<<
"The sub-tree is like this:"
<<endl;
bstree.ascend(bstree.get(
new
IntClass(15)));
cout<<
"-------------------------------------------------"
<<endl;
bstreeStr.insert(
new
StringClass(
"Jim"
,3),
new
StringClass(
"Hello, I'm a student"
,20));
bstreeStr.insert(
new
StringClass(
"Lucy"
,4),
new
StringClass(
"Hello, I'm a teacher"
,20));
bstreeStr.insert(
new
StringClass(
"Brown"
,5),
new
StringClass(
"Hello, I'm a doctor"
,19));
bstreeStr.insert(
new
StringClass(
"Lily"
,4),
new
StringClass(
"Hello, I'm a actor"
,18));
bstreeStr.insert(
new
StringClass(
"Tao"
,3),
new
StringClass(
"Hello, I'm a student"
,20));
bstreeStr.insert(
new
StringClass(
"Peter"
,5),
new
StringClass(
"Hello, I'm a teacher"
,20));
bstreeStr.insert(
new
StringClass(
"John"
,4),
new
StringClass(
"Hello, I'm a doctor"
,19));
bstreeStr.insert(
new
StringClass(
"Tony"
,4),
new
StringClass(
"Hello, I'm a actor"
,18));
bstreeStr.insert(
new
StringClass(
"Linda"
,5),
new
StringClass(
"Hello, I'm a student"
,20));
bstreeStr.insert(
new
StringClass(
"Jurcy"
,5),
new
StringClass(
"Hello, I'm a teacher"
,20));
bstreeStr.insert(
new
StringClass(
"Chern"
,5),
new
StringClass(
"Hello, I'm a doctor"
,19));
bstreeStr.insert(
new
StringClass(
"Rone"
,4),
new
StringClass(
"Hello, I'm a actor"
,18));
bstreeStr.outPut();
cout<<
"-------------------------------------------------"
<<endl;
}
输出结果如下:
附:前面要使用一个队列来进行树的层次遍历,这里将它给出,这是一个模板类
#ifndef QUEUE_H
#define QUEUE_H
#define MAXLEN 20
#include <assert.h>
template
<
class
T>
class
Queue
{
private
:
T data[MAXLEN];
int
head,end;
public
:
Queue();
bool
EnQueue(T next);
T DeQueue();
bool
isFull();
bool
isEmpty();
};
#endif
template
<
class
T>
Queue<T>::Queue()
{
head = 0;
end = 0;
}
template
<
class
T>
bool
Queue<T>::EnQueue(T next)
{
if
(isFull())
return
false
;
data[end] = next;
end=end+1;
if
(end >= MAXLEN)end = 0;
return
true
;
}
template
<
class
T>
T Queue<T>::DeQueue()
{
assert
(!isEmpty());
int
temp=head;
head=head+1;
if
(head>=MAXLEN)
head=0;
return
data[temp];
}
template
<
class
T>
bool
Queue<T>::isFull()
{
if
(end+1==head || (head==0 && end == MAXLEN-1))
return
true
;
return
false
;
}
template
<
class
T>
bool
Queue<T>::isEmpty()
{
if
(head == end)
return
true
;
return
false
;
}
本文出自:http://www.cnblogs.com/xiao-cheng/category/325955.html
- 二叉查找树的基类实现(下)
- 二叉查找树的基类实现(上)
- 二叉查找树的基类实现(中)
- 二叉树类的实现(查找树)
- 二叉查找树的类模板实现
- 二叉查找树(BST)的实现
- 二叉查找树的实现(c++)
- 二叉查找树的实现
- 二叉查找树的实现
- 二叉查找树的实现
- 二叉查找树的实现
- 二叉查找树的实现
- 二叉查找树的实现
- 二叉查找树的实现
- 二叉查找树的实现
- 二叉查找树的实现
- 二叉查找树实现
- 二叉查找树实现
- Tomcat Can't load AMD 64-bit .dll on a IA 32
- 转载:java泛型
- iPhone OS编程指南(一)
- 增加虚拟机可以使用的最大内存
- HDU 4006 The kth great number
- 二叉查找树的基类实现(下)
- 从这里开始
- iPhone OS编程指南(三)
- spring dao到实体的映射
- textarea 字数统计
- python 单元测试 使用摘要
- Vim配置文件(全平台可用)2012-05-01版
- GDI+ 通过流方式操作图片文件,避免文件权限冲突
- 四种求最大子序列和问题的解