摘要:本文讲解了如何使用C++实现了二叉树的创建,添加节点,删除节点,使用递归和非递归方法分别进行前中后遍历,进行层遍历
关键字 :二叉树遍历
二叉树的结构体
typedef struct node
{
int key, visited = 0;
struct node *lChild, *rChild;
}Node, *BST;
这里key是存储节点的值,visited用来辅助判断节点是否被访问,在递归后序遍历时用到。
二叉树的建立
// 建立BST
void createBST(Node * &T, int a[], int n)
{
T = NULL;
int i;
for(i = 0; i < n; i++)
{
BSTInsert(T, a[i]);
}
}
T是根节点,a[]存储节点的值,n是节点的个数
其中BSTInsert(T, a[i])函数的实现如下:
// 在给定的BST中插入结点,其数据域为element, 使之称为新的BST
bool BSTInsert(Node * &p, int element)
{
if(NULL == p) // 空树
{
p = new Node;
//p = (BST *)malloc(sizeof(BST));
p->key = element;
p->lChild = p->rChild = NULL;
return true;
}
if(element == p->key) // BST中不能有相等的值
return false;
if(element < p->key) // 递归
return BSTInsert(p->lChild, element);
return BSTInsert(p->rChild, element); // 递归
}
二叉树的递归遍历
前序遍历
// 先序遍历
void preOrderTraverse(BST T)
{
BST p = T;
if(p)
{
cout << p->key << " ";
preOrderTraverse(p->lChild);
preOrderTraverse(p->rChild);
}
}
中序遍历
// 中序遍历
void midOrderTraverse(BST T)
{
if(T)
{
midOrderTraverse(T->lChild);
cout << T->key << " ";
midOrderTraverse(T->rChild);
}
}
后序遍历
// 后序遍历
void backOrderTraverse(BST T)
{
if(T)
{
backOrderTraverse(T->lChild);
backOrderTraverse(T->rChild);
cout << T->key << " ";
}
}
删除节点
//删除二叉树中与key值相等的节点
bool DeleteBST(BST & T, int key)
{
/* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素节点 */
/* 并返回TRUE;否则返回FALSE */
if(!T)
return false; /* 不存在关键字等于key的数据元素 */
else
{
if(key == T->key)
Delete(T);
else if(key < T->key)
return DeleteBST(T->lChild, key);
else
return DeleteBST(T->rChild, key);
}
}
DeleteBST()的作用是寻找节点值和key值相等的节点,Delete(T)才是真正删除节点的函数。代码如下:
int Delete(BST & p)
{
/* 从二叉排序树中删除节点p, 并重接它的左或右子树 */
BST q, s;
if(!p->lChild && !p->rChild) /* p为叶子节点 */
p = 0;
else if(!p->lChild) /* 左子树为空,重接右子树 */
{
q = p;
p = p->rChild;
free(q);
}
else if(!p->rChild) /* 右子树为空,重接左子树 */
{
q = p;
p = p->lChild;
free(q);
}
else /* 左右子树均不为空 */
{
q = p;
s = p->lChild;
while(s->rChild) /* 转左,然后向右走到尽头*/
{
q = s;
s = s->rChild;
}
p->key = s->key;
if(q != p) /* 判断是否执行上述while循环 */
q->rChild = s->lChild; /* 执行上述while循环,重接右子树 */
else
q->lChild = s->lChild; /* 未执行上述while循环,重接左子树 */
free(s);
}
return true;
}
删除节点要遵循以下规则:
(1)删除节点为叶节点,直接删除;否则,执行步骤(2)
(2)当删除节点的右子树为空时,直接把左子树的根节点作为删除节点的左孩子;否则,执行步骤(3);
(3)当删除节点的左子树为空时,直接把右子树的根节点作为删除节点的右孩子;否则,执行步骤(4);
(4)当左子树和右子树都不为空时,设删除节点为p节点,先寻找p节点的左孩子,设为s节点,若s存在右孩子,执行步骤a;否则,执行步骤b;
a.以s节点为起始点,一直寻找s的最右端孩子,设为s节点,s节点的父节点设为q节点。此时把s的左子树作为q节点的右子树,s节点直接替代p节点;
b.p节点的右子树作为s节点的右子树,并且用s节点替换p节点。
步骤图解如下:
1.树的原图
2.执行规则(1)
删除叶子节点7,则直接删除
3.执行规则(2)
删除值为5的节点,由于该节点右子树为空,只需把节点5的左子树作为父节点6的左子树,然后删除节点5。
4.执行规则(3)
删除值为11的节点,由于该节点左子树为空,只需把节点11的右子树作为父节点10的右子树,然后删除节点11。
5.执行规则(4)a条例
删除值为10的节点,由于节点10的第一个左孩子6存在右子树,故寻找节点6的最右端孩子节点,为9,把节点9的左子树作为父节点6的右子树,并且以节点9替换要删除节点10,然后删除节点10。
6.执行规则(4)b条例
删除值为13的节点,由于节点13的第一个左孩子12不存在右子树,故把13的右子树作为12的右子树,以节点12替代节点13,删除节点13。
二叉树的非递归遍历
前序遍历
void preSearch(BST T)
{
stack<BST> s;
BST p = T;
while(p)
{
while(p)
{
cout << p->key << " ";
s.push(p);
p = p->lChild;
}
while(!s.empty() && !p)
{
p = s.top();
s.pop();
p = p->rChild;
}
}
}
中序遍历
void midSearch(BST T)
{
BST p = T;
stack<BST> s;
while(p)
{
while(p)
{
s.push(p);
p = p->lChild;
}
while(!s.empty() && !p)
{
p = s.top();
cout << p->key << " ";
s.pop();
p = p->rChild;
}
//cout << p->key << " ";
}
}
后序遍历
void backSearch(BST T)
{
BST cur;
BST pre = NULL;
s.push(T);
while(!s.empty())
{
cur = s.top();
if((cur->lChild == NULL&&cur->rChild == NULL) ||
(pre != NULL && (pre == cur->lChild || pre == cur->rChild)))
{
cout << cur->key << " "; //如果当前结点没有孩子结点或者孩子节点都已被访问过
s.pop();
pre = cur;
}
else
{
if(cur->rChild != NULL)
s.push(cur->rChild);
if(cur->lChild != NULL)
s.push(cur->lChild);
}
}
}
层序遍历
void levelOrderTraverse(BST T)
{
BST p = T;
if(p)
{
de.push_back(p);
}
while(!de.empty())
{
p = de.front();
if(p->lChild)
{
de.push_back(p->lChild);
}
if(p->rChild)
{
de.push_back(p->rChild);
}
p = de.front();
cout << p->key << " ";
de.pop_front();
}
}
源代码
#include <iostream>
#include <deque>
#include <stack>
using namespace std;
// BST的结点
typedef struct node
{
int key, visited = 0;
struct node *lChild, *rChild;
}Node, *BST;
deque<BST> de;
stack<BST> s;
// 在给定的BST中插入结点,其数据域为element, 使之称为新的BST
bool BSTInsert(Node * &p, int element)
{
if(NULL == p) // 空树
{
p = new Node;
//p = (BST *)malloc(sizeof(BST));
p->key = element;
p->lChild = p->rChild = NULL;
return true;
}
if(element == p->key) // BST中不能有相等的值
return false;
if(element < p->key) // 递归
return BSTInsert(p->lChild, element);
return BSTInsert(p->rChild, element); // 递归
}
// 建立BST
void createBST(Node * &T, int a[], int n)
{
T = NULL;
int i;
for(i = 0; i < n; i++)
{
BSTInsert(T, a[i]);
}
}
#pragma region 递归
// 先序遍历
void preOrderTraverse(BST T)
{
BST p = T;
if(p)
{
cout << p->key << " ";
preOrderTraverse(p->lChild);
preOrderTraverse(p->rChild);
}
}
// 中序遍历
void midOrderTraverse(BST T)
{
if(T)
{
midOrderTraverse(T->lChild);
cout << T->key << " ";
midOrderTraverse(T->rChild);
}
}
// 后序遍历
void backOrderTraverse(BST T)
{
if(T)
{
backOrderTraverse(T->lChild);
backOrderTraverse(T->rChild);
cout << T->key << " ";
}
}
int Delete(BST & p)
{
/* 从二叉排序树中删除节点p, 并重接它的左或右子树 */
BST q, s;
if(!p->lChild && !p->rChild) /* p为叶子节点 */
p = 0;
else if(!p->lChild) /* 左子树为空,重接右子树 */
{
q = p;
p = p->rChild;
free(q);
}
else if(!p->rChild) /* 右子树为空,重接左子树 */
{
q = p;
p = p->lChild;
free(q);
}
else /* 左右子树均不为空 */
{
q = p;
s = p->lChild;
while(s->rChild) /* 转左,然后向右走到尽头*/
{
q = s;
s = s->rChild;
}
p->key = s->key;
if(q != p) /* 判断是否执行上述while循环 */
q->rChild = s->lChild; /* 执行上述while循环,重接右子树 */
else
q->lChild = s->lChild; /* 未执行上述while循环,重接左子树 */
free(s);
}
return true;
}
bool DeleteBST(BST & T, int key)
{
/* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素节点 */
/* 并返回TRUE;否则返回FALSE */
if(!T)
return false; /* 不存在关键字等于key的数据元素 */
else
{
if(key == T->key)
Delete(T);
else if(key < T->key)
return DeleteBST(T->lChild, key);
else
return DeleteBST(T->rChild, key);
}
}
#pragma endregion
#pragma region 非递归
void levelOrderTraverse(BST T)
{
BST p = T;
if(p)
{
de.push_back(p);
}
while(!de.empty())
{
p = de.front();
if(p->lChild)
{
de.push_back(p->lChild);
}
if(p->rChild)
{
de.push_back(p->rChild);
}
p = de.front();
cout << p->key << " ";
de.pop_front();
}
}
void preSearch(BST T)
{
stack<BST> s;
BST p = T;
while(p)
{
while(p)
{
cout << p->key << " ";
s.push(p);
p = p->lChild;
}
while(!s.empty() && !p)
{
p = s.top();
s.pop();
p = p->rChild;
}
}
}
void midSearch(BST T)
{
BST p = T;
stack<BST> s;
while(p)
{
while(p)
{
s.push(p);
p = p->lChild;
}
while(!s.empty() && !p)
{
p = s.top();
cout << p->key << " ";
s.pop();
p = p->rChild;
}
//cout << p->key << " ";
}
}
void backSearch(BST T)
{
BST cur;
BST pre = NULL;
s.push(T);
while(!s.empty())
{
cur = s.top();
if((cur->lChild == NULL&&cur->rChild == NULL) ||
(pre != NULL && (pre == cur->lChild || pre == cur->rChild)))
{
cout << cur->key << " "; //如果当前结点没有孩子结点或者孩子节点都已被访问过
s.pop();
pre = cur;
}
else
{
if(cur->rChild != NULL)
s.push(cur->rChild);
if(cur->lChild != NULL)
s.push(cur->lChild);
}
}
}
#pragma endregion
int main(void)
{
int a[11] = { 10,6,11,5,9,13,4,8,12,14,7};
int n = 11;
BST T;
// 并非所有的a[]都能构造出BST,所以,最好对createBST的返回值进行判断
createBST(T, a, n);
cout << "前序遍历:" << endl;
preOrderTraverse(T);
cout << endl;
preSearch(T);
cout << endl;
cout << "中序遍历:" << endl;
midOrderTraverse(T);
cout << endl;
midSearch(T);
cout << endl;
cout << "后序遍历:" << endl;
backOrderTraverse(T);
cout << endl;
backSearch(T);
cout << endl;
//cout << DeleteBST(T,2) << endl;
cout << "层序遍历:" << endl;
levelOrderTraverse(T);
cout << "删除2之后" << endl;
DeleteBST(T, 2);
levelOrderTraverse(T);
cout << endl;
return 0;
}