纯C++代码详解二叉树相关操作

纯C++代码详解二叉树相关操作

介绍

二叉树是一种非常常见的数据结构,适用于处理需要具有层级关系的数据。在本文中,我们将详细讲解如何使用C++来实现二叉树的基本操作,包括创建、遍历、插入、删除等。

创建二叉树

定义二叉树节点

在C++中实现二叉树的概念,需要先定义二叉树节点的结构,代码如下:

struct BinaryTreeNode
{
    int value; // 节点的值
    BinaryTreeNode* left; // 左子节点
    BinaryTreeNode* right; // 右子节点
};

创建二叉树

创建一个二叉树对象,需要一个根节点,代码如下:

BinaryTreeNode* root = new BinaryTreeNode;
root->value = 1;
root->left = new BinaryTreeNode;
root->left->value = 2;
root->left->left = NULL;
root->left->right = NULL;
root->right = new BinaryTreeNode;
root->right->value = 3;
root->right->left = NULL;
root->right->right = NULL;

这个二叉树的结构是这样的:

      1
     / \
    2   3

遍历二叉树

遍历二叉树有三种常见的方法:前序遍历、中序遍历、后序遍历。以下分别为三种遍历方式的代码。

前序遍历

前序遍历的顺序是:根节点 -> 左子树 -> 右子树。

void PreOrderTraversal(BinaryTreeNode* node)
{
    if(node)
    {
        cout << node->value << "->";
        PreOrderTraversal(node->left);
        PreOrderTraversal(node->right);
    }
}

中序遍历

中序遍历的顺序是:左子树 -> 根节点 -> 右子树。

void InOrderTraversal(BinaryTreeNode* node)
{
    if(node)
    {
        InOrderTraversal(node->left);
        cout << node->value << "->";
        InOrderTraversal(node->right);
    }
}

后序遍历

后序遍历的顺序是:左子树 -> 右子树 -> 根节点。

void PostOrderTraversal(BinaryTreeNode* node)
{
    if(node)
    {
        PostOrderTraversal(node->left);
        PostOrderTraversal(node->right);
        cout << node->value << "->";
    }
}

插入节点

插入左子节点

如果一个节点没有左子节点,我们可以通过如下代码给它插入一个:

BinaryTreeNode* node = new BinaryTreeNode;
node->value = 4;
node->left = NULL;
node->right = NULL;

root->left->left = node;

这个二叉树的结构变成了这样:

      1
     / \
    2   3
   /
  4

插入右子节点

如果一个节点没有右子节点,我们可以通过如下代码给它插入一个:

BinaryTreeNode* node = new BinaryTreeNode;
node->value = 5;
node->left = NULL;
node->right = NULL;

root->left->right = node;

这个二叉树的结构变成了这样:

      1
     / \
    2   3
   / \
  4   5

删除节点

删除叶子节点

如果要删除一个叶子节点,只需要把它的父节点的指针指向NULL即可。

delete root->left->right;
root->left->right = NULL;

这个二叉树的结构变成了这样:

      1
     / \
    2   3
   /
  4

删除非叶子节点

删除非叶子节点需要注意两种情况:被删除节点有一个子节点或两个子节点。对于只有一个子节点的节点,我们将其子节点向上移动即可。对于有两个子节点的节点,我们需要找到其后继节点,用后继节点替换被删除节点。

// 寻找一个节点的后继节点
BinaryTreeNode* GetSuccessor(BinaryTreeNode* node)
{
    if(node->right == NULL)
        return NULL;
    BinaryTreeNode* p = node->right;
    while(p->left != NULL)
        p = p->left;
    return p;
}

// 删除节点
void DeleteNode(BinaryTreeNode* root, int value)
{
    if(!root)
        return;
    if(root->value == value)
    {
        if(!root->left && !root->right)
        {
            delete root;
            root = NULL;
        }
        else if(root->left && !root->right)
        {
            BinaryTreeNode* temp = root->left;
            *root = *temp;
            delete temp;
        }
        else if(!root->left && root->right)
        {
            BinaryTreeNode* temp = root->right;
            *root = *temp;
            delete temp;
        }
        else
        {
            BinaryTreeNode* successor = GetSuccessor(root);
            root->value = successor->value;
            DeleteNode(root->right, successor->value);
        }
    }
    else if(root->value > value)
        DeleteNode(root->left, value);
    else
        DeleteNode(root->right, value);
}

示例

下面是一个完整的二叉树的示例,显示了如何创建、遍历、插入和删除二叉树节点。

#include <iostream>

using namespace std;

struct BinaryTreeNode
{
    int value;
    BinaryTreeNode* left;
    BinaryTreeNode* right;
};

void PreOrderTraversal(BinaryTreeNode* node)
{
    if(node)
    {
        cout << node->value << "->";
        PreOrderTraversal(node->left);
        PreOrderTraversal(node->right);
    }
}

void InOrderTraversal(BinaryTreeNode* node)
{
    if(node)
    {
        InOrderTraversal(node->left);
        cout << node->value << "->";
        InOrderTraversal(node->right);
    }
}

void PostOrderTraversal(BinaryTreeNode* node)
{
    if(node)
    {
        PostOrderTraversal(node->left);
        PostOrderTraversal(node->right);
        cout << node->value << "->";
    }
}

BinaryTreeNode* GetSuccessor(BinaryTreeNode* node)
{
    if(node->right == NULL)
        return NULL;
    BinaryTreeNode* p = node->right;
    while(p->left != NULL)
        p = p->left;
    return p;
}

void DeleteNode(BinaryTreeNode* root, int value)
{
    if(!root)
        return;
    if(root->value == value)
    {
        if(!root->left && !root->right)
        {
            delete root;
            root = NULL;
        }
        else if(root->left && !root->right)
        {
            BinaryTreeNode* temp = root->left;
            *root = *temp;
            delete temp;
        }
        else if(!root->left && root->right)
        {
            BinaryTreeNode* temp = root->right;
            *root = *temp;
            delete temp;
        }
        else
        {
            BinaryTreeNode* successor = GetSuccessor(root);
            root->value = successor->value;
            DeleteNode(root->right, successor->value);
        }
    }
    else if(root->value > value)
        DeleteNode(root->left, value);
    else
        DeleteNode(root->right, value);
}

int main()
{
    BinaryTreeNode* root = new BinaryTreeNode;
    root->value = 1;
    root->left = new BinaryTreeNode;
    root->left->value = 2;
    root->left->left = NULL;
    root->left->right = NULL;
    root->right = new BinaryTreeNode;
    root->right->value = 3;
    root->right->left = NULL;
    root->right->right = NULL;

    cout << "preorder traversal: ";
    PreOrderTraversal(root);
    cout << endl;

    cout << "inorder traversal: ";
    InOrderTraversal(root);
    cout << endl;

    cout << "postorder traversal: ";
    PostOrderTraversal(root);
    cout << endl;

    BinaryTreeNode* node = new BinaryTreeNode;
    node->value = 4;
    node->left = NULL;
    node->right = NULL;

    root->left->left = node;

    cout << "preorder traversal after inserting 4: ";
    PreOrderTraversal(root);
    cout << endl;

    BinaryTreeNode* node2 = new BinaryTreeNode;
    node2->value = 5;
    node2->left = NULL;
    node2->right = NULL;

    root->left->right = node2;

    cout << "preorder traversal after inserting 5: ";
    PreOrderTraversal(root);
    cout << endl;

    DeleteNode(root, 2);

    cout << "preorder traversal after deleting 2: ";
    PreOrderTraversal(root);
    cout << endl;

    return 0;
}

这个程序输出的结果如下:

preorder traversal: 1->2->3->
inorder traversal: 2->1->3->
postorder traversal: 2->3->1->
preorder traversal after inserting 4: 1->2->4->3->
preorder traversal after inserting 5: 1->2->4->5->3->
preorder traversal after deleting 2: 1->4->5->3->

可以看到,通过这个代码示例,我们实现了(1) 创建一个二叉树;(2) 实现三种遍历方式;(3) 向二叉树中插入节点;(4) 删除二叉树中的节点。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:纯C++代码详解二叉树相关操作 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 一起来看看C语言线性表的线性链表

    一起来看看C语言线性表的线性链表攻略 线性链表概述 线性链表是线性表的一种实现方式,它通过每个节点中包含指向下一个节点的指针来实现表中元素之间的链接,可以动态地增加、删除节点。线性链表分为带头节点的链表和不带头节点的链表,其中带头节点的链表更为常见。 实现思路 结构体定义 我们可以定义一个结构体来表示每个节点,例如: typedef struct ListN…

    数据结构 2023年5月17日
    00
  • 【ACM组合数学 | 错排公式】写信

    题目链接:https://ac.nowcoder.com/acm/contest/54484/B 题意很简单,但是数据范围偏大。 错排公式 首先来推导一下错排公式: \[D(n) = n!\sum_{k=0}^{n}\frac{(-1)^k}{k!} \] 设一个函数: \[S_i表示一个排列中p_i = i的方案数 \] 那么我们可以知道: \[D(n) …

    算法与数据结构 2023年4月17日
    00
  • C语言实现通用数据结构之通用椎栈

    C语言实现通用数据结构之通用椎栈 概述 通用椎栈(Generic Linked List Stack),简称GLL Stack,是一种通用的数据结构,能够以动态的方式存储和访问任意类型的数据。GLL Stack 采用链表实现,可以进行进栈(push)、出栈(pop)、查看栈顶元素(peek)、判断栈是否为空(isEmpty)等基本操作。 基本操作 数据结构定…

    数据结构 2023年5月17日
    00
  • Java 数据结构线性表之顺序存储详解原理

    Java 数据结构线性表之顺序存储详解原理 一、什么是线性表 线性表(Linear List)指的是同一类数据元素的集合,而且这些元素之间是有序的。线性表具有两个显著的特点:第一,有且仅有一个被称为“第一个”的数据元素;第二,有且仅有一个被称为“最后一个”的数据元素;此外,除第一个和最后一个数据元素外,其它数据元素均有且仅有一个直接前驱和一个直接后继。 二、…

    数据结构 2023年5月17日
    00
  • c语言实现单链表算法示例分享

    下面是详细的攻略。 C语言实现单链表算法示例分享 什么是单链表 单链表是一种数据结构,它由一个个节点组成,每个节点包含两个部分:一个是数据部分,另一个是指针部分,指针部分指向下一个节点的位置。单链表的节点是动态分配的,可以随时插入、删除,是一种非常灵活的数据结构。 为什么要使用单链表 在进行一些操作时,数组或者普通的指针会遇到很多麻烦。比如在删除数组元素时,…

    数据结构 2023年5月17日
    00
  • C++数据结构关于栈迷宫求解示例

    C++数据结构关于栈迷宫求解示例攻略 在本篇攻略中,我们将使用C++数据结构中的栈来解决迷宫问题,具体将通过两个示例来详细讲解该方法。首先介绍一下栈的概念。 栈的概念 栈是一种“后入先出”的数据结构,即最后压入栈中的元素会首先被弹出,而最早压入栈中的元素会最后被弹出。栈的基本操作有入栈(push)、出栈(pop)、判断是否为空以及读取栈顶元素等。 迷宫问题 …

    数据结构 2023年5月17日
    00
  • 栈(Stack)

    概述 栈就是一种 只允许在表尾进行插入和删除操作 的 线性表 栈的特点 先进后出 ,在表尾进行插入和删除操作 数组实现栈 crown crown:使用bottom来确定栈顶所在数组的下标,默认为 -1 空栈 当空栈时 ,crown = -1 栈是否为空 当 crown = -1 时 ,栈为空 ,不能 遍历 ,出栈 , 获取栈顶元素 栈是否已满 当 crown…

    算法与数据结构 2023年4月19日
    00
  • CSP-何以包邮?

    题目描述 新学期伊始,适逢顿顿书城有购书满 x 元包邮的活动,小 P 同学欣然前往准备买些参考书。一番浏览后,小 P 初步筛选出 n 本书加入购物车中,其中第 i 本(1≤i≤n)的价格为 ai 元。考虑到预算有限,在最终付款前小 P 决定再从购物车中删去几本书(也可以不删),使得剩余图书的价格总和 m 在满足包邮条件(m≥x)的前提下最小。 试帮助小 P …

    算法与数据结构 2023年5月11日
    00
合作推广
合作推广
分享本页
返回顶部