二叉排序树
- 在使用链表的时候,我们碰到的问题都是一对一的线性结构,然而当碰到一对多的时候,链表就无法使用。此时我们需要一对多的数据结构——树。树是非线性的数据结构。
现实生活的树长这样
而今天要介绍的二叉树和树确实长得很像。
关于二叉树的性质
- 每个节点最多可以有两个子节点,并且子树都有左右之分,次序不能颠倒。
- 二叉树的第i层最多有2的i次方-1个节点,第一层为图中最上层A,往下依次增加。
- 深度为n的二叉树,最多有2的n次方-1个节点,深度就是从上往下的层数,图中A为一层,BC为一层,DEFG为一层,所以为三层。
二叉查找树
是二叉树的一种,称为查找树,是因为有着以下的特殊性质。
1. 若任意结点的左子树不为空,那么所有左子树的结点的值要小于其父节点的值
2. 若任意结点的右子树不为空,那么所有右子树的结点的值要大于其父节点的值
3. 没有任意两个节点的值一样
在每次插入时都要进行对比,所以形成了在根节点的左边都是比根节点小的数据,在右边则是比根节点大的数据。并且不会出现重复数据。
.h文件
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
const int MAX_SIZE = 32767;
const int MIN_SIZE = 0;
class Node
{
public:
int data;
Node* left;
Node* right;
Node() :data(0), left(NULL), right(NULL) {}
};
class Binary
{
public:
Binary() :root(NULL), size(0) {}
~Binary() {}
int getSize()const;//获取树的大小
void insertNode(int data);
void preTravel();//先序遍历
void midTravel();//中序遍历
void postTravel();//后序遍历
Node* searchKey(int value);//通过value查找某个结点
void removeTree();//删除整棵树
void removeNode(int vlaue);
private:
Node* insert(Node* root, int data);
void pretraveltree(Node* root);
void midtraveltree(Node* root);
void posttraveltree(Node* root);
Node* searchtree(Node* root, int value);
void removealltree(Node* root);
private:
Node* root;//树的根节点
int size;//树的大小
};
1.创建二叉树及插入数据
void Binary::insertNode(int data)
{
if (MAX_SIZE <= getSize())
{
cerr << "二叉树的结点个数已经到达最大值,无法插入!";
return;
}
root = insert(root, data);
}
Node* Binary::insert(Node* proot, int data)
{
if (proot == NULL)//当前树为空的情况
{
Node* nNode = new Node();
nNode->data = data;
proot = nNode;
size++;
return proot;
}
if (proot->data > data)//如果当前值小于结点值,往左边插入
{
proot->left = insert(proot->left, data);
}
else if (proot->data < data)//如果当前值大于结点值,往右边插入
{
proot->right = insert(proot->right, data);
}
else if (proot->data == data)//等于则不插入值
{
return proot;
}
size++;
return proot;
}
2.二叉树的遍历
1. 先序遍历:中->左->右的顺序遍历,如上图按照顺序来为6425879,第一个永远为根节点
2. 中序遍历:左->中->右的顺序遍历,如上图按照顺序来为2456789,在根节点左边的在树中结点也在左边,在根节点右边的在树中也在右边
3. 后序遍历:左->右->中的顺序遍历,如上图按照顺序来为2547986,最后一个遍历的永远是根节点
3.删除某一个结点
1. 如图,如果删除结点为叶子结点,例如1、4、6、8,直接删除即可。
2. 当删除的结点不为叶子结点,有一个左子树或者右子树时,就要子承父业。例如删除2这个结点时,那么久变成了下图图2。
图23.当删除的结点的左右子节点都存在时,使用其中序遍历相邻结点作为删除结点的替代,然后将用来替代的结点删除。如下图所示中序遍历的顺序为2、4、6、8、10、12、14、16、18、20、22。
**假设我们要删除8这个结点,那么在按照中序遍历,我们可以用6或者10来替代它。如下图
附测试cpp代码,.h文件在上面
```cpp
#include "Tree.h"
int Binary::getSize()const
{
return size;
}
void Binary::insertNode(int data)
{
if (MAX_SIZE <= getSize())
{
cerr << "二叉树的结点个数已经到达最大值,无法插入!";
return;
}
root = insert(root, data);
}
Node* Binary::insert(Node* proot, int data)
{
if (proot == NULL)//当前树为空的情况
{
Node* nNode = new Node();
nNode->data = data;
proot = nNode;
size++;
return proot;
}
if (proot->data > data)//如果当前值小于结点值,往左边插入
{
proot->left = insert(proot->left, data);
}
else if (proot->data < data)
{
proot->right = insert(proot->right, data);
}
else if (proot->data == data)
{
return proot;
}
size++;
return proot;
}
void Binary::preTravel()
{
pretraveltree(root);
}
void Binary::pretraveltree(Node* proot)
{
if (NULL != proot)
{
cout << proot->data << " ";
pretraveltree(proot->left);
pretraveltree(proot->right);
}
}
void Binary::midTravel()
{
midtraveltree(root);
}
void Binary::midtraveltree(Node* proot)
{
if (NULL != proot)
{
midtraveltree(proot->left);
cout << proot->data << " ";
midtraveltree(proot->right);
}
}
void Binary::postTravel()
{
posttraveltree(root);
}
void Binary::posttraveltree(Node* proot)
{
if (NULL != proot)
{
posttraveltree(proot->left);
posttraveltree(proot->right);
cout << proot->data << " ";
}
}
Node* Binary::searchKey(int value)
{
if (NULL == root)
{
cerr << "树是空的" << endl;
return NULL;
}
return searchtree(root, value);
}
Node* Binary::searchtree(Node* proot,int value)
{
if (proot->data == value)
{
return proot;
}
else if (proot->data > value)
{
return searchtree(proot->left, value);
}
else if (proot->data < value)
{
return searchtree(proot->right, value);
}
}
void Binary::removeTree()
{
if (NULL == root)
{
cerr << "树已经是空的了" << endl;
}
removealltree(root);
}
void Binary::removealltree(Node* proot)
{
if (NULL != proot)
{
removealltree(proot->left);
removealltree(proot->right);
delete proot;
proot = NULL;
}
size = 0;
}
void Binary::removeNode(int value)
{
if (NULL == root)
{
cerr << "树是空的" << endl;
return;
}
Node* pNode = NULL;
Node* pDel = root;
while (pDel)//该循环用于找到需要删除的结点和其父节点
{
if (value == pDel->data)
{
break;
}
else if (value > pDel->data)
{
pNode = pDel;//用于记录父节点
pDel = pDel->right;
}
else if (value < pDel->data)
{
pNode = pDel;
pDel = pDel->left;
}
}
if (NULL == pDel)
{
cerr << "该value不存在于树中" << endl;
return;
}
if ((pDel->left == NULL) && (pDel->right == NULL))//1.左子树和右子树都为空的情况,为叶节点
{
if (pDel == root)//整棵树只有一个节点的情况下
{
root = NULL;
delete pDel;
pDel = NULL;
size--;
return;
}
if (pNode->left = pDel)
{
pNode->left = NULL;
}
else if (pNode->right = pDel)//父节点的右边为需要删除的结点
{
pNode->right = NULL;
}
delete pDel;
pDel = NULL;
size--;
}
else if ((pDel->right == NULL) && (pDel->left != NULL))//2.只有左子树的情况
{
if (pDel == root)//删除结点为root结点时
{
root = pDel->left;
}
else
{
if (pNode->left == pDel)//父结点的左节点为需要删除的结点时,将父节点跳过原来的需要删除的子节点,直接指向子节点的左子树
{
pNode->left = pDel->left;
}
else if (pNode->right = pDel)
{
pNode->right = pDel->left;
}
}
size--;
}
else if ((pDel->right != NULL) && (pDel->left == NULL))//3.只存在右子树的情况
{
if (pDel == root)
{
root = pDel->right;
}
else
{
if (pNode->left = pDel)
{
pNode->left = pDel->right;
}
else if (pNode->right = pDel)
{
pNode->right = pDel->right;
}
}
size--;
}
else if ((pDel->right != NULL) && (pDel->left != NULL))
{
Node* pSuc = pDel->right;
pNode = pDel;
while (pSuc->left)
{
pNode = pSuc;
pSuc = pSuc->left;
}
pDel->data = pSuc->data;
if (pSuc == pNode->left)
{
pNode->left = pSuc->right;
}
else if (pSuc == pNode->right)
{
pNode->right = pSuc->right;
}
pDel = pSuc;
delete pDel;
pDel = NULL;
size--;
}
}
int main()
{
Binary tree;
tree.insertNode(16);
tree.insertNode(20);
tree.insertNode(18);
tree.insertNode(22);
tree.insertNode(12);
tree.insertNode(14);
tree.insertNode(8);
tree.insertNode(10);
tree.insertNode(4);
tree.insertNode(2);
tree.insertNode(6);
tree.removeNode(12);
//tree.preTravel();
tree.midTravel();
//tree.postTravel();
return 0;
}