/*-------------------------------------
* 日期:2019-12-2
* 作者:SJF0115
* 题目: 二叉树各种遍历
* 博客
------------------------------------*/
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
// 二叉树节点结构
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x):val(x),left(nullptr),right(nullptr){}
};
// 1.创建二叉树
void CreateTree(TreeNode* &root){
int val;
//按先序次序输入二叉树中结点的值,‘-1’表示空树
cin>>val;
// 空节点
if(val == -1){
root = nullptr;
return;
}//if
root = new TreeNode(val);
//构造左子树
CreateTree(root->left);
//构造右子树
CreateTree(root->right);
}
// 2.1 递归先序遍历
void PreOrder(TreeNode* root,vector<int> &result){
if(root == nullptr){
return;
}//if
result.push_back(root->val);
// 左子树
PreOrder(root->left,result);
// 右子树
PreOrder(root->right,result);
}
// 2.2 非递归先序遍历
void PreOrder2(TreeNode* root,vector<int> &result){
if(root == nullptr){
return;
}//if
stack<TreeNode*> s;
s.push(root);
TreeNode *node;
while(!s.empty()){
node = s.top();
s.pop();
result.push_back(node->val);
// 右子树
if(node->right){
s.push(node->right);
}//if
// 左子树
if(node->left){
s.push(node->left);
}//if
}//while
}
// 3.1 递归中序遍历
void InOrder(TreeNode* root,vector<int> &result){
if(root == nullptr){
return;
}//if
// 左子树
InOrder(root->left,result);
result.push_back(root->val);
// 右子树
InOrder(root->right,result);
}
// 3.2 非递归中序遍历
void InOrder2(TreeNode* root,vector<int> &result){
if(root == nullptr){
return;
}//if
stack<TreeNode*> s;
TreeNode *node = root;
while(node != nullptr || !s.empty()){
// 左子树
if(node != nullptr){
s.push(node);
node = node->left;
}//if
// 右子树
else{
node = s.top();
s.pop();
result.push_back(node->val);
node = node->right;
}
}//while
}
// 4.1 递归后序遍历
void PostOrder(TreeNode* root,vector<int> &result){
if(root == nullptr){
return;
}//if
// 左子树
PostOrder(root->left,result);
// 右子树
PostOrder(root->right,result);
result.push_back(root->val);
}
// 4.2 非递归后序遍历
void PostOrder2(TreeNode *root,vector<int> &result) {
if(root == nullptr){
return;
}//if
stack<TreeNode*> s;
s.push(root);
TreeNode *node;
while(!s.empty()){
node = s.top();
s.pop();
result.insert(result.begin(),node->val);
// 左子树
if(node->left){
s.push(node->left);
}//if
// 右子树
if(node->right){
s.push(node->right);
}//if
}//while
}
// 5 层次遍历
void LevelOrder(TreeNode* root,vector<int> &result){
if(root == nullptr){
return;
}//if
queue<TreeNode*> queue;
queue.push(root);
TreeNode *node;
while(!queue.empty()){
node = queue.front();
queue.pop();
result.push_back(node->val);
// 左子树
if(node->left){
queue.push(node->left);
}//if
// 右子树
if(node->right){
queue.push(node->right);
}//if
}//while
}
// 输出结果
void Print(vector<int> result){
int size = result.size();
for(int i = 0;i < size;++i){
cout<<result[i]<<" ";
}//for
cout<<endl;
}
int main(){
freopen("C:\\Users\\Administrator\\Desktop\\c++.txt", "r", stdin);
TreeNode* root = nullptr;
vector<int> result;
// 创建二叉树
cout<<"1. 创建二叉树"<<endl;
CreateTree(root);
cout<<"-----------------------------"<<endl;
cout<<"2.1 递归先序遍历"<<endl;
PreOrder(root,result);
Print(result);
result.clear();
cout<<"-----------------------------"<<endl;
cout<<"2.2 非递归先序遍历"<<endl;
PreOrder2(root,result);
Print(result);
result.clear();
cout<<"-----------------------------"<<endl;
cout<<"3.1 递归中序遍历"<<endl;
InOrder(root,result);
Print(result);
result.clear();
cout<<"-----------------------------"<<endl;
cout<<"3.2 非递归中序遍历"<<endl;
InOrder2(root,result);
Print(result);
result.clear();
cout<<"-----------------------------"<<endl;
cout<<"4.1 递归后序遍历"<<endl;
PostOrder(root,result);
Print(result);
result.clear();
cout<<"-----------------------------"<<endl;
cout<<"4.2 非递归后序遍历"<<endl;
PostOrder2(root,result);
Print(result);
result.clear();
cout<<"-----------------------------"<<endl;
cout<<"5 层次遍历"<<endl;
LevelOrder(root,result);
Print(result);
result.clear();
cout<<"-----------------------------"<<endl;
return 0;
}
关于二叉树的学习,需要说明的是:它并不难,不仅不难,而且它非常简单。初次接触树的时候,我也觉得它似乎很难;而之所产生这种感觉主要是由于二叉树有一大堆陌生的概念、性质等内容。而当我真正的实现了二叉树再回过头来看它的相关概念和性质的时候,觉得原来它是如此的简单!因此,建议在学习二叉树的时候:先对二叉树基本的概念、性质有个基本了解,遇到难懂的知识点,可以画图来帮助理解;在有个基本的概念之后,再亲自动手实现二叉查找树(这一点至关重要!);最后再回过头来总结一下二叉树的理论知识时,你会发现——它的确很简单!在代码实践中,我以"二叉查找树,而不是单纯的二叉树"为例子进行说明,单纯的二叉树非常简单,实际使用很少。况且掌握了二叉查找树,二叉树也就自然掌握了。
#ifndef _BINARY_SEARCH_TREE_H_
#define _BINARY_SEARCH_TREE_H_
typedef int Type;
typedef struct BSTreeNode{
Type key; // 关键字(键值)
struct BSTreeNode *left; // 左孩子
struct BSTreeNode *right; // 右孩子
struct BSTreeNode *parent; // 父结点
}Node, *BSTree;
// 前序遍历"二叉树"
void preorder_bstree(BSTree tree);
// 中序遍历"二叉树"
void inorder_bstree(BSTree tree);
// 后序遍历"二叉树"
void postorder_bstree(BSTree tree);
// (递归实现)查找"二叉树x"中键值为key的节点
Node* bstree_search(BSTree x, Type key);
// (非递归实现)查找"二叉树x"中键值为key的节点
Node* iterative_bstree_search(BSTree x, Type key);
// 查找最小结点:返回tree为根结点的二叉树的最小结点。
Node* bstree_minimum(BSTree tree);
// 查找最大结点:返回tree为根结点的二叉树的最大结点。
Node* bstree_maximum(BSTree tree);
// 找结点(x)的后继结点。即,查找"二叉树中数据值大于该结点"的"最小结点"。
Node* bstree_successor(Node *x);
// 找结点(x)的前驱结点。即,查找"二叉树中数据值小于该结点"的"最大结点"。
Node* bstree_predecessor(Node *x);
// 将结点插入到二叉树中,并返回根节点
Node* insert_bstree(BSTree tree, Type key);
// 删除结点(key为节点的值),并返回根节点
Node* delete_bstree(BSTree tree, Type key);
// 销毁二叉树
void destroy_bstree(BSTree tree);
// 打印二叉树
void print_bstree(BSTree tree, Type key, int direction);
#endif
/**
* 二叉搜索树(C语言): C语言实现的二叉搜索树。
*
* @author skywang
* @date 2013/11/07
*/
#include <stdio.h>
#include <stdlib.h>
#include "bstree.h"
/*
* 前序遍历"二叉树"
*/
void preorder_bstree(BSTree tree)
{
if(tree != NULL)
{
printf("%d ", tree->key);
preorder_bstree(tree->left);
preorder_bstree(tree->right);
}
}
/*
* 中序遍历"二叉树"
*/
void inorder_bstree(BSTree tree)
{
if(tree != NULL)
{
inorder_bstree(tree->left);
printf("%d ", tree->key);
inorder_bstree(tree->right);
}
}
/*
* 后序遍历"二叉树"
*/
void postorder_bstree(BSTree tree)
{
if(tree != NULL)
{
postorder_bstree(tree->left);
postorder_bstree(tree->right);
printf("%d ", tree->key);
}
}
/*
* (递归实现)查找"二叉树x"中键值为key的节点
*/
Node* bstree_search(BSTree x, Type key)
{
if (x==NULL || x->key==key)
return x;
if (key < x->key)
return bstree_search(x->left, key);
else
return bstree_search(x->right, key);
}
/*
* (非递归实现)查找"二叉树x"中键值为key的节点
*/
Node* iterative_bstree_search(BSTree x, Type key)
{
while ((x!=NULL) && (x->key!=key))
{
if (key < x->key)
x = x->left;
else
x = x->right;
}
return x;
}
/*
* 查找最小结点:返回tree为根结点的二叉树的最小结点。
*/
Node* bstree_minimum(BSTree tree)
{
if (tree == NULL)
return NULL;
while(tree->left != NULL)
tree = tree->left;
return tree;
}
/*
* 查找最大结点:返回tree为根结点的二叉树的最大结点。
*/
Node* bstree_maximum(BSTree tree)
{
if (tree == NULL)
return NULL;
while(tree->right != NULL)
tree = tree->right;
return tree;
}
/*
* 找结点(x)的后继结点。即,查找"二叉树中数据值大于该结点"的"最小结点"。
*/
Node* bstree_successor(Node *x)
{
// 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
if (x->right != NULL)
return bstree_minimum(x->right);
// 如果x没有右孩子。则x有以下两种可能:
// (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
// (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。
Node* y = x->parent;
while ((y!=NULL) && (x==y->right))
{
x = y;
y = y->parent;
}
return y;
}
/*
* 找结点(x)的前驱结点。即,查找"二叉树中数据值小于该结点"的"最大结点"。
*/
Node* bstree_predecessor(Node *x)
{
// 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
if (x->left != NULL)
return bstree_maximum(x->left);
// 如果x没有左孩子。则x有以下两种可能:
// (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
// (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。
Node* y = x->parent;
while ((y!=NULL) && (x==y->left))
{
x = y;
y = y->parent;
}
return y;
}
/*
* 创建并返回二叉树结点。
*
* 参数说明:
* key 是键值。
* parent 是父结点。
* left 是左孩子。
* right 是右孩子。
*/
static Node* create_bstree_node(Type key, Node *parent, Node *left, Node* right)
{
Node* p;
if ((p = (Node *)malloc(sizeof(Node))) == NULL)
return NULL;
p->key = key;
p->left = left;
p->right = right;
p->parent = parent;
return p;
}
/*
* 将结点插入到二叉树中
*
* 参数说明:
* tree 二叉树的根结点
* z 插入的结点
* 返回值:
* 根节点
*/
static Node* bstree_insert(BSTree tree, Node *z)
{
Node *y = NULL;
Node *x = tree;
// 查找z的插入位置
while (x != NULL)
{
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y==NULL)
tree = z;
else if (z->key < y->key)
y->left = z;
else
y->right = z;
return tree;
}
/*
* 新建结点(key),并将其插入到二叉树中
*
* 参数说明:
* tree 二叉树的根结点
* key 插入结点的键值
* 返回值:
* 根节点
*/
Node* insert_bstree(BSTree tree, Type key)
{
Node *z; // 新建结点
// 如果新建结点失败,则返回。
if ((z=create_bstree_node(key, NULL, NULL, NULL)) == NULL)
return tree;
return bstree_insert(tree, z);
}
/*
* 删除结点(z),并返回根节点
*
* 参数说明:
* tree 二叉树的根结点
* z 删除的结点
* 返回值:
* 根节点
*/
static Node* bstree_delete(BSTree tree, Node *z)
{
Node *x=NULL;
Node *y=NULL;
if ((z->left == NULL) || (z->right == NULL) )
y = z;
else
y = bstree_successor(z);
if (y->left != NULL)
x = y->left;
else
x = y->right;
if (x != NULL)
x->parent = y->parent;
if (y->parent == NULL)
tree = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
if (y != z)
z->key = y->key;
if (y!=NULL)
free(y);
return tree;
}
/*
* 删除结点(key为节点的键值),并返回根节点
*
* 参数说明:
* tree 二叉树的根结点
* z 删除的结点
* 返回值:
* 根节点
*/
Node* delete_bstree(BSTree tree, Type key)
{
Node *z, *node;
if ((z = bstree_search(tree, key)) != NULL)
tree = bstree_delete(tree, z);
return tree;
}
/*
* 销毁二叉树
*/
void destroy_bstree(BSTree tree)
{
if (tree==NULL)
return ;
if (tree->left != NULL)
destroy_bstree(tree->left);
if (tree->right != NULL)
destroy_bstree(tree->right);
free(tree);
}
/*
* 打印"二叉树"
*
* tree -- 二叉树的节点
* key -- 节点的键值
* direction -- 0,表示该节点是根节点;
* -1,表示该节点是它的父结点的左孩子;
* 1,表示该节点是它的父结点的右孩子。
*/
void print_bstree(BSTree tree, Type key, int direction)
{
if(tree != NULL)
{
if(direction==0) // tree是根节点
printf("%2d is root\n", tree->key);
else // tree是分支节点
printf("%2d is %2d's %6s child\n", tree->key, key, direction==1?"right" : "left");
print_bstree(tree->left, tree->key, -1);
print_bstree(tree->right,tree->key, 1);
}
}
/**
* C 语言: 二叉查找树
*
* @author skywang
* @date 2013/11/07
*/
#include <stdio.h>
#include "bstree.h"
static int arr[]= {1,5,4,3,2,6};
#define TBL_SIZE(a) ( (sizeof(a)) / (sizeof(a[0])) )
int main()
{
int i, ilen;
BSTree root=NULL;
printf("== 依次添加: ");
ilen = TBL_SIZE(arr);
for(i=0; i<ilen; i++)
{
printf("%d ", arr[i]);
root = insert_bstree(root, arr[i]);
}
printf("\n== 前序遍历: ");
preorder_bstree(root);
printf("\n== 中序遍历: ");
inorder_bstree(root);
printf("\n== 后序遍历: ");
postorder_bstree(root);
printf("\n");
printf("== 最小值: %d\n", bstree_minimum(root)->key);
printf("== 最大值: %d\n", bstree_maximum(root)->key);
printf("== 树的详细信息: \n");
print_bstree(root, root->key, 0);
printf("\n== 删除根节点: %d", arr[3]);
root = delete_bstree(root, arr[3]);
printf("\n== 中序遍历: ");
inorder_bstree(root);
printf("\n");
// 销毁二叉树
destroy_bstree(root);
}