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

yizhihongxing

纯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++实现LeetCode(211.添加和查找单词-数据结构设计)

    首先,我们需要先了解一下题目的要求和限制,以及具体的解题思路。 题目描述 设计一个支持添加、删除、查找单词的数据结构。添加和删除单词的操作需要支持普通词和通配符’.’。查找单词只支持普通词,不支持通配符’.’。所有单词都是非空的。 解题思路 这道题可以使用前缀树(Trie树)来实现。 首先,我们需要定义一个单词类,它包含两个字段:单词字符串和单词长度。然后,…

    数据结构 2023年5月17日
    00
  • java实现队列queue数据结构详解

    Java实现队列(Queue)数据结构详解 什么是队列(Queue) 队列(Queue),是一种先进先出(First In First Out, FIFO)的数据结构,即最先进入队列的元素也会最先出队列。 队列具备两个基本操作:入队(enqueue)和出队(dequeue)。入队操作将元素加入到队列的尾部,出队操作将元素从队列头部取出并删除。 Java中的Q…

    数据结构 2023年5月17日
    00
  • 数据结构之哈夫曼树与哈夫曼编码

    一、背景 编码是信息处理的基础(重新表示信息)。 普通的编码是等长编码,例如7位的ASCIL编码,对出现频率不同的字符都使用相同的编码长度。但其在传输和存储等情况下编码效率不高。 可使用不等长编码,来压缩编码:高频字符编码长度更短,低频字符编码长度更长。   [例] 将百分制的考试成绩转换成五分制的成绩 按顺序分别编码。 按频率分别编码(高频短编码,类似于香…

    算法与数据结构 2023年4月17日
    00
  • JavaScript队列数据结构详解

    JavaScript队列数据结构详解 本文将为大家详细讲解JavaScript队列数据结构的相关知识。 什么是队列数据结构 队列是一种线性数据结构,它只允许在队列的两端进行插入和删除操作。在队列中,新元素插入到队列的末尾,也称为队尾。而删除操作则是从队列的前面删除元素,也称为队首。 将元素插入队列的操作称为入队,将元素删除队列的操作称为出队。除此之外,还有一…

    数据结构 2023年5月17日
    00
  • C语言数据结构之单链表操作详解

    C语言数据结构之单链表操作详解 本文将详细讲解C语言数据结构中单链表的操作方法,包括单链表的建立、遍历、插入、删除等操作,并提供两个示例进行说明。 单链表的定义 单链表是一种常见的动态数据结构,由若干节点组成,每个节点通常包含一个数据元素和一个指向下一个节点的指针。单链表最后一个节点的指针指向NULL,表示链表的结尾。 单链表的节点定义 单链表的节点通常由结…

    数据结构 2023年5月17日
    00
  • java数据结构基础:稀疏数组

    Java数据结构基础:稀疏数组 在开发过程中,我们需要处理一些稀疏矩阵(大部分元素为0)的数据。这时候,使用稀疏数组是比较高效的方法。 什么是稀疏数组 稀疏数组是由很多元素值相同的元素组成,这些元素的值通常为0。而这些值不同时都存储在一个数组中会浪费很多内存空间。因此,我们使用稀疏数组来存储这些元素。 稀疏数组的定义: 稀疏数组的行数可以理解为矩阵的行数,而…

    数据结构 2023年5月17日
    00
  • Java数据结构之对象比较详解

    Java数据结构之对象比较详解 在Java中,比较两个对象的内容是否相等一直是程序员们比较困惑的问题。本文将详细探讨Java中对象比较的几种方式,并给出相应的示例。 基本类型比较 在Java中,比较基本类型的值可以使用双等号(==)进行判断。例如: int a = 1; int b = 1; boolean result = a == b; System.o…

    数据结构 2023年5月17日
    00
  • 查询json的数据结构的8种方式简介

    查询json的数据结构的8种方式简介 在处理JSON数据时,经常需要提取特定的数据或获取某个属性的值。这时候就需要使用JSON的查询语言来进行查询操作。本文将介绍8种常用的JSON查询方式,帮助大家更方便、快捷地查询和分析JSON数据。 1. 点语法 使用点语法(.)查询JSON数据是最简单、最常用的方式,通过指定属性名来获取相应的值。例如,假设有以下的JS…

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