二叉树的链式结构实现

二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个节点最多只能有两棵子树,且有左右之分

文章目录


前言

由于二叉树的链式结构的一些增删查改没有什么意义,但为什么需要学习呢?

1、主要是为了学习后面二叉树更复杂的数据结构铺垫(红黑树、AVL树、搜索二叉树、B树(多叉平衡搜索树)……)。

2、由于大部分的题目中普通二叉树涉及较多。


提示:以下是本篇文章正文内容,下面案例可供参考

一、前置说明

在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。此处手动快速创建一棵简单的二叉树,快速进入二叉树 操作学习,等二叉树结构了解的差不多时,反过头再来研究二叉树真正的创建方式。

二、二叉树的遍历

1.二叉树的手动创建

代码如下(示例):

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	BinaryTreeNode* left;
	BinaryTreeNode* right;
}BTNode;
BTNode* BuyNode(BTDataType x)
{
	BTNode* node = new BTNode;
	assert(node);
    node->data=x;
	node->left = nullptr;
	node->right = nullptr;
	return node;
}
BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);

	node1->left = node2;
	node1->right = node4;
	node4->left = node5;
	node4->right = node6;
	node2->left = node3;
	return node1;
}

2.前序、中序以及后续的遍历

1.前序遍历 (Preorder Traversal 亦称先序遍历 )—— 访问根结点的操作发生在遍历其左右子树之前
图示:

void PreOrder(BTNode* root)
{
	if (root == nullptr)
		return;
	cout << root->data<<" ";
	PreOrder(root->left);
	PreOrder(root->right);
}
2. 中序遍历 (Inorder Traversal)—— 访问根结点的操作发生在遍历其左右子树之中(间)。
void InOrder(BTNode* root)
{
	if (root == nullptr)
		return;
	InOrder(root->left);
	cout << root->data << " ";
	InOrder(root->right);
}

 3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

void PostOrder(BTNode* root)
{
	if (root == nullptr)
		return;
	PostOrder(root->left);
	
	PostOrder(root->right);

	cout << root->data << " ";
}

3.节点的个数以及高度等

1.求节点的数量

int BinaryTreeSize(BTNode* root)
{
   if (root == nullptr)
		return 0;
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

2.求叶子节点的数量

int BinaryLeafSize(BTNode* root)
{
	if (root == nullptr)
		return 0;
	if (root->left == nullptr && root->right == nullptr)
		return 1;
	return BinaryLeafSize(root->left) + BinaryLeafSize(root->right);
}

3.求第K层的节点数

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k >= 1);
	if (root == nullptr)
		return 0;
	if (k == 1)
		return 1;
	return BinaryTreeLevelKSize(root->left,k-1) + BinaryTreeLevelKSize(root->right,k-1);
	
}

4.查找值为x的节点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == nullptr)
		return nullptr;
	if (root->data == x)
		return root;
	BTNode* ret1 = BinaryTreeFind(root->left, x);
	if (ret1)
		return ret1;
	BTNode* ret2 = BinaryTreeFind(root->left, x);
	if (ret2)
		return ret2;
	return nullptr;
}

5、求树的高度

int BinaryTreeDepth(BTNode*root)
{
	if (root == nullptr)
		return 0;
	int LeftDepth = BinaryTreeDepth(root->left) ;
	int RightDepth = BinaryTreeDepth(root->right) ;
	return LeftDepth > RightDepth ? LeftDepth+1 : RightDepth+1;

}

6、二叉树的销毁

void BinaryTreeDestroy(BTNode* root)
{
	if (root == nullptr)
		return;
	BinaryTreeDestroy(root->left);
	BinaryTreeDestroy(root->right);
	delete root;
}

7、判断二叉树是否是完全二叉树

int BinaryTreeComplete(BTNode* root)
{
	queue<BTNode*>q;
	if (root)
		q.push(root);
	while (!q.empty())
	{
		BTNode* front = q.front();
		q.pop();
		if (front)
		{
			q.push(front->left);
			q.push(front->right);
		}
		else
		{   //遇到空以后跳出循环
			break;
		}
		//如果后面全是空则是完全二叉树
		//如果空后面还有非空不是完全二叉树
		while (!q.empty())
		{
			BTNode* front = q.front();
			q.pop();
			if (front)
			{

				return false;
			}
		}
		return true;

	}
}

四、关于二叉树的题目

1.单值二叉树。Oj链接

第一种方法:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool PreOrder(TreeNode*root,int BasicValue)//前序遍历
    {
        if(root==nullptr)
          return true;
        if(root->val!=BasicValue)
          return false;
        return PreOrder(root->left,BasicValue)&&PreOrder(root->right,BasicValue);
        
        
    }
    bool isUnivalTree(TreeNode* root) {
        if(root==nullptr)
            return true;
    
        return PreOrder(root,root->val);


    }
};

第二种方法:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isUnivalTree(TreeNode* root) {
        if(root==nullptr)
           return true;
        if(root->left&&root->left->val!=root->val)
         {
             return false;
         }
         if(root->right&&root->right->val!=root->val)
         {
             return false;
         }
         return isUnivalTree(root->left)&&isUnivalTree(root->right);

    }
};

2.二叉树最大深度。OJ链接

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root==nullptr)
           return 0;
        int LeftDepth=maxDepth(root->left);
        int RightDepth=maxDepth(root->right);
        return LeftDepth>RightDepth?LeftDepth+1:RightDepth+1;

    }
};

3.检查两颗树是否相同。OJ链接

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p==nullptr&&q==nullptr)//p,q两树都为空
          return true;
       if(p==nullptr||q==nullptr)//p,q两树其中一个为空
          return false;
        if(p->val!=q->val)//p,q两树都不为空
          return false;
        return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);


    }
};

 4.对称二叉树。OJ链接

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSymmetricCompare(TreeNode*root1,TreeNode*root2)
    {
        if(root1==nullptr&&root2==nullptr)//根节点都为空
          return true;
        if(root1==nullptr||root2==nullptr)//根节点不都为空
          return false;
        if(root1->val!=root2->val)//左子树的val不等于右子树的val继续
          return false;
        return isSymmetricCompare(root1->left,root2->right)&&isSymmetricCompare(root1->right,root2->left);//左子树的左孩子等于右子树的右孩子,左子树的右孩子等于右子树的左孩子
    }
    bool isSymmetric(TreeNode* root) {
        if(root==nullptr)
          return true;
        return isSymmetricCompare(root->left,root->right);

    }
};

5.二叉树的前序遍历。 OJ链接

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void PreOrder(TreeNode*root,vector<int>&v)
    {
        if(root==nullptr)//前序遍历先访问根节点若为空直接返回
          return;
        v.push_back(root->val);//若不为空尾插到容器中
        PreOrder(root->left,v);//再遍历左子树和右子树
        PreOrder(root->right,v);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>v;
       PreOrder(root,v);
       return v;
    }
};

6.二叉树中序遍历 。OJ链接

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
     void InOrder(TreeNode*root,vector<int>&v)
    {
        if(root==nullptr)
          return;
        InOrder(root->left,v);//中序遍历先访问左子树再遍历根
        v.push_back(root->val);//若不为空尾插到容器中
        InOrder(root->right,v);//最后再遍历右子树
    }
    vector<int> inorderTraversal(TreeNode* root) {
       vector<int>v;
       InOrder(root,v);
       return v;
    }

};

7.二叉树的后序遍历 。OJ链接

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void PostOrder(TreeNode*root,vector<int>&v)
    {
        if(root==nullptr)
          return;
        PostOrder(root->left,v);//后序序遍历先访问左子树若为空直接返回
        PostOrder(root->right,v);//再遍历右子树和根
        v.push_back(root->val);//若不为空尾插到容器中
    }
     vector<int> postorderTraversal(TreeNode* root) {
       vector<int>v;
       PostOrder(root,v);
       return v;
    }
};

8.另一颗树的子树。OJ链接

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p==nullptr&&q==nullptr)//p,q两树都为空
          return true;
       if(p==nullptr||q==nullptr)//p,q两树其中一个为空
          return false;
        if(p->val!=q->val)//p,q两树都不为空
          return false;
        return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);


    }

    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        if(root==nullptr)//若为空即不符合
          return false;
        if(isSameTree(root,subRoot))//遍历与当前树进行比较
           return true;
        return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);


    }
};

9.二叉树的构建及遍历。OJ链接

#include<iostream>
using namespace std;
class BinaryTreeNode
{
public:
    BinaryTreeNode(char ch='0')
        :val(ch)
        ,left(nullptr)
        ,right(nullptr)
        {
            
        }

    BinaryTreeNode* BuyTreeNode(char ch)
    {
        BinaryTreeNode* node = new BinaryTreeNode(ch);
        return node;
    }
    BinaryTreeNode* CreateTree(string str, int& pi)
     {

            if (str[pi] == '#')
            {
                pi++;
                return nullptr;
            }

            BinaryTreeNode* root = BuyTreeNode(str[pi++]);
    
            root->left = CreateTree(str, pi);

            root->right = CreateTree(str, pi);

            return root;

            }

        

    void InOrder(BinaryTreeNode* root)
    {
        if (root == nullptr)
            return;
        InOrder(root->left);
        cout << root->val<<" ";
        InOrder(root->right);
    }
private:
    char val;
    BinaryTreeNode* left;
    BinaryTreeNode* right;

};
int main()
{
    string str1;
    int i = 0;
    cin >> str1;
    BinaryTreeNode tree;
    BinaryTreeNode* root = tree.CreateTree(str1, i);
    tree.InOrder(root);

}

五.层序遍历

除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在
层数为 1 ,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第 2 层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
void LevelOrder(BTNode* root)
{
	queue<BTNode*>q;
	if (root)
		q.push(root);
	while (!q.empty())
	{
		auto front = q.front();
		cout << front->data;
		q.pop();
		if (front->left)
			q.push(root->left);
		if (front->right)
			q.push(root->right);
	}
}

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...