数据结构与算法--二叉排序树(C++实现)

前言

这里的二叉树是指二叉排序树。二叉树也是常用的数据结构。一棵二叉树由根节点(可以为空)和左右子树(也是二叉树)构成。通常情况下,二叉树的效率比线性链表高,因为二叉树上的查询、插入等操作即相当于二分法操作,时间复杂度为 O ( log ⁡ 2 N ) O(\log_{2}{N}) O(log2N)。但二叉树也很容易失衡,极端情况下将退化为线性链表。本文用C++实现二叉树的算法,是C++、数据结构及算法学习的一个小练习。供大家参考。

二叉树上的操作

二叉树用递归定义,其上的操作基本也是基于递归定义的。编程比较方便。
1、遍历。二叉树上的遍历分为前序、中序和后序遍历。本文只讨论中序遍历。
2、搜索。二叉树的天生优势就在于搜索。相当于二分法查询。效率比较高。
3、插入。在二叉树的合适位置插入节点。当然,插入后必须仍然是二叉排序树。
4、删除。节点的删除是二叉树操作中比较难一点的。难点在于删除节点后新节点的选取以及要保持该数据结构仍然是二叉排序树。

数据结构和算法描述

节点

节点(Node)分为两部分,数据和链接部分。数据部分存储数据,可以根据实际情况分为若干字段。本文数据部分分两个字段:key和data。key字段用于排序和查找节点。本文允许key重复,因此查找和删除节点要遍历所有相同key值的节点。data则存储节点的其它信息。链接部分是两个指针,分别指向左子树和右子树。C++代码如下:

struct Node {
   
    int key;
    string data;
    Node *lpt=nullptr, *rpt=nullptr;
    Node(int ky, const string &da, Node *lp=nullptr, Node *rp=nullptr) : key(ky), data(da), lpt(lp), rpt(rp) {
   }
};

算法描述

遍历

仅作中序遍历。前序和后续遍历算法从略。
(1)如果当前节点是空,返回;否则(2)。
(2)遍历左子树。
(3)访问/输出当前节点。
(4)遍历右子树。

搜索

(1)如果是空树,返回;否则(2)。
(2)如果给定参数小于当前节点的 k e y key key值,在左子树搜索;否则(3)。
(3)如果给定参数等于当前节点的 k e y key key值,命中,返回当前节点指针;否则(4)。
(4)在右子树搜索。

插入

(1)如果是空树,在当前插入新节点,否则(2)。
(2)如果新节点键值小于当前节点键值,在左子树插入新节点,否则(3)。
(3)在右子树插入新节点。

删除

(1)如果是空树,返回;否则(2)。
(2)如果参数小于当前节点键值,则在左子树中删除等于给定键值的节点;否则(3)。
(3)如果参数等于当前节点键值,命中。删除当前节点,分以下两种情况:
(3.1)如果当前节点左子树不是空,找到其左子树的最右边的节点(即循环搜索左子树的右节点,直到其右指针为空。),令此最右节点的右指针指向待删除节点右子树。选取待删除节点的左子树的根作为新的根(即以左子树的根取代待删除节点),删除待删除节点。递归删除当前节点右子树。
(3.2)如果当前节点左子树是空,选取待删除节点右子树的根作为新的根,删除待删除节点。递归删除当前节点右子树。
(4)如果不满足(3)的条件,即参数大于当前节点键值,则在右子树中删除等于给定键值的节点。

查找最大节点

(1)如果是空树,返回空指针;否则(2)。
(2)如果右子树非空,返回右子树的最大节点;否则(3)。
(3)返回当前节点指针。

查找最小节点

(1)如果是空树,返回空指针;否则(2)。
(2)如果左子树非空,返回左子树的最小节点;否则(3)。
(3)返回当前节点指针。

类的定义

二叉树定义成一个类,其上定义了构造函数、析构函数、插入、搜索、删除、判断空函数(isEmpty())等等操作,以及指向左右子树的指针。类的方法中,插入、搜索、遍历、删除等方法都有两个定义,一个为公有方法,供实例调用;另一个是私有方法(前面加下划线"_",以作区分),用于递归实现相应的操作。这样做的原因是公用方法应该尽量隐蔽节点信息。用户(实例)只通过键值(key)来访问数据,而不涉及数据存储的细节。当然,私有方法也可以和公有方法同名,而不必前面加下划线来区分。因为函数重载可以区分不同的函数调用。但文中为了避免混淆,还是将它们定义成不同的名字。具体C++代码如下:

struct Node {
   
    int key;
    string data;
    Node *lpt=nullptr, *rpt=nullptr;
    Node(int ky, const string &da, Node *lp=nullptr, Node *rp=nullptr) : key(ky), data(da), lpt(lp), rpt(rp) {
   }
};
class BinaryTree
{
       
    public:
        BinaryTree();
        virtual ~BinaryTree();
        BinaryTree(const BinaryTree& other);
        BinaryTree& operator=(const BinaryTree& other);
        void insertNode(int ky, const string &da);
        void deleteNode()
  • 4
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉排序树的二叉链表存储结构的类型定义如下: typedef struct node{ int data; //用整数表示一个结点的名 struct node *LChild,*RChild; //左右指针域 }BSTNode,*BSTree; 设计算法并编写程序求解以下几个问题。 8 12 14 10 7 3 15 6 2 4 1 5 11 9 13 16 13 (1)键盘输入一个元素序列创建一棵二叉排序树,输出该二叉排序树的中序遍历序列; 例如,若输入 45,24,55,12,37,53,60,23,40,70 则创建的二叉排序树为: 输出结果为:12 23 24 37 40 45 53 55 60 70 (2)在(1)中所得的二叉排序树中插入一个值为 58 的结点,再输出它的中序遍历序列,输出 结果为:12 23 24 37 40 45 53 55 58 60 70 (3)在(1)中所得的二叉排序树中删除值为 45 的结点,再输出它的中序遍历序列,输出结果 为:12 23 24 37 40 53 55 58 60 70 (4)利用(1)中所得的二叉排序树的所有叶子结点构造一个带头结点的单链表 L。要求不能 破坏这棵二叉排序树。所得的单链表 L 如下。 输出该链表各结点的值,输出结果为:23 40 53 70 (5)设计算法将(1)中所得的二叉排序树的左右子树进行交换,由于二叉树是一种递归定义, 所以子树的左右两棵子树也要相交换,依此类推。最后输出所得到的二叉树的中序遍历序列。 例如,经过上述操作后,(1)中所得的二叉排序树变为如下形式。 输出该二叉树的中序序列,结果为:70 60 55 53 45 40 37 24 23 12 (6)设计算法统计并输出(1)中所得的二叉排序树中只有一个孩子结点的结点个数。输出结 果为:3(7)在(1)中所得的二叉排序树中,设计算法并编写程序输出结点 40 的所有祖先结点。输 出结果为:45 24 37
以下是基于 C++ 的代码实现,包括所需的数据结构算法函数: ```cpp #include <iostream> using namespace std; // 定义二叉排序树的结点 struct BSTNode { int data; BSTNode* left; BSTNode* right; }; // 查找算法函数 BSTNode* BSTSearch(BSTNode* root, int key) { if (root == nullptr || root->data == key) { return root; } if (key < root->data) { return BSTSearch(root->left, key); } return BSTSearch(root->right, key); } // 插入算法函数 BSTNode* BSTInsert(BSTNode* root, int key) { if (root == nullptr) { root = new BSTNode; root->data = key; root->left = root->right = nullptr; } else if (key < root->data) { root->left = BSTInsert(root->left, key); } else { root->right = BSTInsert(root->right, key); } return root; } // 建立二叉排序树的插入算法 BSTNode* BSTCreate() { BSTNode* root = nullptr; int n; cout << "请输入结点个数: "; cin >> n; cout << "请输入" << n << "个结点的值: "; for (int i = 0; i < n; i++) { int key; cin >> key; root = BSTInsert(root, key); } return root; } // 二叉排序树删除一个结点的操作实现 BSTNode* BSTDelete(BSTNode* root, int key) { if (root == nullptr) { return root; } if (key < root->data) { root->left = BSTDelete(root->left, key); } else if (key > root->data) { root->right = BSTDelete(root->right, key); } else { if (root->left == nullptr) { BSTNode* temp = root->right; delete root; return temp; } else if (root->right == nullptr) { BSTNode* temp = root->left; delete root; return temp; } BSTNode* temp = root->right; while (temp->left != nullptr) { temp = temp->left; } root->data = temp->data; root->right = BSTDelete(root->right, temp->data); } return root; } // 中序遍历打印二叉排序树 void BSTPrint(BSTNode* root) { if (root == nullptr) { return; } BSTPrint(root->left); cout << root->data << " "; BSTPrint(root->right); } int main() { BSTNode* root = BSTCreate(); cout << "建立的二叉排序树为: "; BSTPrint(root); int key; cout << "\n请输入要删除的结点的值: "; cin >> key; root = BSTDelete(root, key); cout << "删除结点 " << key << " 后的二叉排序树为: "; BSTPrint(root); return 0; } ``` 这个程序允许用户输入要插入的结点值,然后建立一个二叉排序树。用户可以输入一个要删除的结点的值,如果该值存在于树中,则将其删除。最后,程序打印剩余的二叉排序树

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值