二叉查找树的基类实现(下)

来源:互联网 发布: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())

        elseif(theKey->Compare(p->getKey()) == 1)

        p=p->getRight();

        else//如果找到了相同的关键字则成功返回

        returnp;

    }

    returnNULL;

}

//插入一个节点,如果节点关键字已经存在则覆盖,否则插入到叶子节点处

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())

        elseif(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;

    elseif(todelete->getParent()->getLeft()==todelete)

        todelete->getParent()->setLeft(nextNode);

    else

        todelete->getParent()->setRight(nextNode);

    //节点成功删除,删完后在考虑将原来节点的后续节点值的替换

    if(todelete!=deletedNode)

    {

        deletedNode->setKey(todelete->getKey());

        deletedNode->setValue(todelete->getValue());

    }

    //返回被删除的节点

    returntodelete;

}

  

//计算左右的宽度,使用递归算法

int BSTree::calWidth(BinaryTreeNode *p)

{

    if(p!=NULL)

    {

        intleftWidth=0;//左宽度

        intrightWidth=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);//设置左右宽度

        //返回本节点为根的子树总宽度

        returnleftWidth+rightWidth;

    }

}

  

//按照层次遍历子树并且打印出来

voidBSTree::ascend(BinaryTreeNode *p)

{   

      

    calWidth(p);//计算左右子树的宽度

  

    p->setLeftOutPutLen(p->getLeftWidth());//设置最顶层的左边预留宽度

  

    //下面要用队列实现树的层次遍历

    Queue<BinaryTreeNode *> Q;

    Q.EnQueue(p);

    intnumber=0;//存储下一层的元素个数

    intnumberLeave=1;//这一层还剩下多少元素

    BinaryTreeNode *dep;//保存当前从队列弹出的节点指针

  

    intpreLeftWidth=0;

    //存储前一个节点的左宽度,以便后面一个节点的打印

    //如果当前节点在最开始,则前一节点左宽度为0

  

    boolfirstIn=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++;//下层节点加一

            }

  

            intleftOutPutLen=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(inti=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则可以输出任何子树

voidBSTree::outPut()

{

    BinaryTreeNode *temp=root;

    ascend(temp);

}

  

BinaryTreeNode *BSTree::tree_minimum(BinaryTreeNode *p)

{

    if(p==NULL)

    returnNULL;

    BinaryTreeNode *pp=p;

    while(pp->getLeft()!=NULL)

       pp=pp->getLeft();

    returnpp;

}

  

BinaryTreeNode *BSTree::tree_maximum(BinaryTreeNode *p)

{

    if(p==NULL)

    returnNULL;

    BinaryTreeNode *pp=p;

    while(pp->getRight()!=NULL)

       pp=pp->getRight();

    returnpp;

}

  

//返回已知节点的后续节点

//如果这个节点有右子数,则返回右子树的最小节点

//否则向父节点寻找,找到第一个向右转的父节点为止

BinaryTreeNode *BSTree::tree_successor(BinaryTreeNode *p)

{

    if(p==NULL)return NULL;

       BinaryTreeNode *pp=p;

    if(pp->getRight()!=NULL)

       returntree_minimum(pp->getRight());

    BinaryTreeNode *y=p->getParent();

    while(y!=NULL && pp==y->getRight())

    {

       pp=y;

       y=y->getParent();

    }

    returny;

}

  

BinaryTreeNode *BSTree::getRoot()

{

    returnroot;

}

 

 

二叉查找树的基类实现(终)

下面举一个具体使用这个数据结构的例子,由于前面的缺点,这里

显得比较麻烦,也比较耗资源,但确实使用到了多态的好处

main.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
#include <iostream>
#include "BSTree.h"
#include "IntClass.h"
#include "StringClass.h"
usingnamespace std;
int main()
{
BSTree bstree;
BSTree bstreeStr;
  
bstree.insert(newIntClass(10),newStringClass("Tao",3));
bstree.insert(newIntClass(5),newStringClass("Tao",3));
bstree.insert(newIntClass(15),newStringClass("Lily",4));
bstree.insert(newIntClass(3),newStringClass("Tom",3));
bstree.insert(newIntClass(7),newStringClass("John",4));
bstree.insert(newIntClass(13),newStringClass("Peter",5));
bstree.insert(newIntClass(17),newStringClass("Joson",5));
bstree.insert(newIntClass(2),newStringClass("Tao",3));
bstree.insert(newIntClass(4),newStringClass("Tao",3));
bstree.insert(newIntClass(6),newStringClass("Tao",3));
bstree.insert(newIntClass(8),newStringClass("Lucy",4));
bstree.insert(newIntClass(11),newStringClass("Jim",3));
bstree.insert(newIntClass(14),newStringClass("Brown",5));
bstree.insert(newIntClass(16),newStringClass("Tao",3));
bstree.insert(newIntClass(18),newStringClass("Tao",3));
bstree.insert(newIntClass(1),newStringClass("Tao",3));
bstree.insert(newIntClass(9),newStringClass("Tao",3));
bstree.insert(newIntClass(12),newStringClass("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(newIntClass(15)));
cout<<"-------------------------------------------------"<<endl;
  
bstreeStr.insert(newStringClass("Jim",3),newStringClass("Hello, I'm a student",20));
bstreeStr.insert(newStringClass("Lucy",4),newStringClass("Hello, I'm a teacher",20));
bstreeStr.insert(newStringClass("Brown",5),newStringClass("Hello, I'm a doctor",19));
bstreeStr.insert(newStringClass("Lily",4),newStringClass("Hello, I'm a actor",18));
bstreeStr.insert(newStringClass("Tao",3),newStringClass("Hello, I'm a student",20));
bstreeStr.insert(newStringClass("Peter",5),newStringClass("Hello, I'm a teacher",20));
bstreeStr.insert(newStringClass("John",4),newStringClass("Hello, I'm a doctor",19));
bstreeStr.insert(newStringClass("Tony",4),newStringClass("Hello, I'm a actor",18));
bstreeStr.insert(newStringClass("Linda",5),newStringClass("Hello, I'm a student",20));
bstreeStr.insert(newStringClass("Jurcy",5),newStringClass("Hello, I'm a teacher",20));
bstreeStr.insert(newStringClass("Chern",5),newStringClass("Hello, I'm a doctor",19));
bstreeStr.insert(newStringClass("Rone",4),newStringClass("Hello, I'm a actor",18));
bstreeStr.outPut();
cout<<"-------------------------------------------------"<<endl;
}
?
1
输出结果如下:

输出结果

附:前面要使用一个队列来进行树的层次遍历,这里将它给出,这是一个模板类

?
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
#ifndef QUEUE_H
#define QUEUE_H
#define MAXLEN 20
#include <assert.h>
template<classT>
classQueue
{
private:
    T data[MAXLEN];
    inthead,end;
public:
    Queue();
    boolEnQueue(T next);
    T DeQueue();
    boolisFull();
    boolisEmpty();
};
#endif
template<classT>
Queue<T>::Queue()
{
    head = 0;
    end = 0;
}
template<classT>
boolQueue<T>::EnQueue(T next)
{
    if(isFull())returnfalse;
    data[end] = next;
    end=end+1;
    if(end >= MAXLEN)end = 0;
    returntrue;
}
template<classT>
T Queue<T>::DeQueue()
{
    assert(!isEmpty());
    inttemp=head;
    head=head+1;
    if(head>=MAXLEN)
        head=0;
    returndata[temp];
}
template<classT>
boolQueue<T>::isFull()
{
    if(end+1==head || (head==0 && end == MAXLEN-1)) 
        returntrue;
    returnfalse;
}
template<classT>
boolQueue<T>::isEmpty()
{
    if(head == end)returntrue;
    returnfalse;
}

 

 

本文出自:http://www.cnblogs.com/xiao-cheng/category/325955.html