文章目录
概念
1.这里,树是一种结构,一对多的数据结构,树结构具备递归特性。
2.孩子节点:当前节点的下一层。
3.父节点:指向当前节点的节点。
4.根:树的第一个节点。
5.叶子:末梢,没有孩子的节点。
6.枝干:除了根和叶子,其它节点都是枝干。
7.高度:当前层节点数,比如上图中的3节点,高度为1。
有二叉树,也有一叉树,三叉树,4叉树。它们的区别在于容许最多的孩子数,一叉树就是链表那种结构。
二叉搜索树(有序二叉树)
二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势。
明白两个概念:
升序:左节点的数据 < 父节点的数据 < 有节点的数据(一般使用这种)
降序:左节点的数据 > 父节点的数据 > 有节点的数据
一般不存相同的数据,如果有,放左边也行,右边也行。
template<class T>
class Tree
{
public:
class Node
{
public:
T data;
Node* pLeft;
Node* pRight;
Node(T insert_data) { data = insert_data; pLeft = NULL; pRight = NULL; }
};
Node* Atree;
Tree(T root_data);
void insert(T insert_data);
void Del(T delete_data);
private:
//这些函数一般不向外界展示
bool _insert(T data, Node*& root);
void _Del(T data, Node*& root);
void main_del(Node*& pDelNode);
};
//构造函数
template<class T>
Tree<T>::Tree(T root_data)
{
Atree = new Node(root_data);
}
//插入函数
template<class T>
void Tree<T>::insert(T insert_data)
{
_insert(insert_data, Atree); //调用递归函数
}
//删除函数
template<class T>
void Tree<T>::Del(T data)
{
_Del(data, Atree);
}
用于插入数据的递归函数
保证每次插入完后,树结构依然有序。
template<class T>
bool Tree<T>::_insert(T data, Node*& root)
{
if (!root)
{
root = new Node(data);
return true;
}
if (root->data >= data)
{
_insert(data, root->pLeft);
}
else
{
_insert(data, root->pRight);
}
return false;
}
从根节点按照大小比较的方式递归寻找合适的位置,然后插入。
用于删除的递归函数
template<class T>
bool Tree<T>::_Del(T data, Node*& root)
{
if (!root)
{
return false;
}
if (data == root->data)
{
main_del(root); //调用删除函数
return true;
}
else if (data < root->data)
{
_Del(data, root->pLeft);
}
else
{
_Del(data, root->pRight);
}
return false;
}
删除的主要函数
要保证删除后依然有序,所以需要做调整,考虑到所有情况。
template<class T>
void Tree<T>::main_del(Node*& pDelNode)
{
//节点是根节点
if (pDelNode == Atree)
{
//没有右孩子,则让左孩子成为新的根节点
if (NULL == pDelNode->pRight)
{
Node* temp = pDelNode->pLeft;
delete pDelNode;
Atree = temp;
return;
}
//有则,先让左孩子成为右孩子的最左孩子,再让右孩子成为新的根节点
else
{
Node* find_temp = pDelNode->pRight;
while (find_temp->pLeft)find_temp = find_temp->pLeft;
find_temp->pLeft = pDelNode->pLeft;
Node* temp = pDelNode->pRight;
delete pDelNode;
Atree = temp;
return;
}
}
//节点不是根节点
else
{
//需要先得到父节点用于连接
Node* pDelParent = Atree;
while (pDelParent)
{
if ((pDelParent->pLeft != NULL && pDelParent->pLeft->data == pDelNode->data)
|| (pDelParent->pRight != NULL && pDelParent->pRight->data == pDelNode->data))break;
else if (pDelParent->data < pDelNode->data)
{
pDelParent = pDelParent->pRight;
}
else
{
pDelParent = pDelParent->pLeft;
}
}
//没有右孩子,则让左孩子成为新的根节点
if (NULL == pDelNode->pRight)
{
Node* temp = pDelNode->pLeft;
delete pDelNode;
//连接,pDelNode是pDelParentNode的右孩子则temp成为pDelParent的右孩子,反之则成为左孩子
if (pDelParent->pLeft == pDelNode)
pDelParent->pLeft = temp;
else
pDelParent->pRight = temp;
return;
}
//有右孩子
else
{
//先让pDelNode的左孩子成为pDelNode的右孩子的最左孩子
Node* find_temp = pDelNode->pRight;
while (find_temp->pLeft)find_temp = find_temp->pLeft;
find_temp->pLeft = pDelNode->pLeft;
//接着pDelNode的右孩子继承pDelNode的位置
Node* temp = pDelNode->pRight;
delete pDelNode;
//pDelNode是pDelParentNode的右孩子则temp成为pDelParent的右孩子,反之则成为左孩子
if (pDelParent->pLeft == pDelNode)
{
pDelParent->pLeft = temp;
}
else
{
pDelParent->pRight = temp;
}
}
}
}