【C++数据结构——查找】二叉排序树(头歌实践教学平台习题)【合集】

简介: 【数据结构——查找】二叉排序树(头歌实践教学平台习题)【合集】目录任务描述相关知识测试说明我的通关代码:测试结果:任务描述本关任务:实现二叉排序树的基本算法。相关知识为了完成本关任务,你需要掌握:二叉树的创建、查找和删除算法。具体如下:(1)由关键字序列(4,9,0,1,8,6,3,5,2,7)创建一棵二叉排序树bt并以括号表示法输出。(2)判断bt是否为一棵二叉排序树。(3)采用递归方法查找关键字为6的结点,并输出其查找路径。(4)分别删除bt中关键

目录😋

任务描述

相关知识

1. 二叉排序树的基本概念

2. 二叉排序树节点结构体定义

3. 创建二叉排序树

4. 判断是否为二叉排序树

5. 递归查找关键字为 6 的结点并输出查找路径

6. 删除二叉排序树中的节点

测试说明

通关代码

测试结果


任务描述

本关任务:实现二叉排序树的基本算法。

相关知识

为了完成本关任务,你需要掌握:

  1. 二叉排序树的基本概念
  2. 二叉排序树节点结构体定义
  3. 创建二叉排序树
  4. 判断是否为二叉排序树
  5. 递归查找关键字为 6 的结点并输出查找路径
  6. 删除二叉排序树中的节点

1. 二叉排序树的基本概念

二叉排序树(Binary Search Tree,也叫二叉查找树)是一种特殊的二叉树,具有以下性质:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值。
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
  • 它的左、右子树也分别为二叉排序树。

2. 二叉排序树节点结构体定义

在 C++ 中,首先需要定义二叉排序树节点的结构体,代码示例如下:

#include <iostream>
using namespace std;
// 二叉树节点结构体定义
template <typename T>
struct TreeNode {
    T val;
    TreeNode<T> *left;
    TreeNode<T> *right;
    TreeNode(T x) : val(x), left(NULL), right(NULL) {}
};
image.gif

3. 创建二叉排序树

根据给定的关键字序列创建二叉排序树的基本思路是,依次将关键字插入到二叉排序树中。插入操作的规则是从根节点开始比较,如果待插入值小于当前节点值就往左子树走,如果大于就往右子树走,直到找到合适的空位置插入。以下是创建二叉排序树的代码实现:

// 插入节点到二叉排序树的函数
template <typename T>
TreeNode<T> *insert(TreeNode<T> *root, T val) {
    if (root == NULL) {
        return new TreeNode<T>(val);
    }
    if (val < root->val) {
        root->left = insert(root->left, val);
    } else {
        root->right = insert(root->right, val);
    }
    return root;
}
// 根据关键字序列创建二叉排序树
template <typename T>
TreeNode<T> *createBST(vector<T> keys) {
    TreeNode<T> *root = NULL;
    for (T key : keys) {
        root = insert(root, key);
    }
    return root;
}
image.gif

然后可以使用以下方式调用创建函数并输出二叉树(以括号表示法输出,这里简单实现一个先序遍历的框架用于输出,实际更完善的括号表示法输出可以处理更多格式细节):

// 先序遍历二叉树(用于简单展示括号表示法输出结构,可完善更准确的括号表示法输出格式)
template <typename T>
void preorderTraversal(TreeNode<T> *root) {
    if (root == NULL) {
        return;
    }
    cout << root->val;
    if (root->left!= NULL || root->right!= NULL) {
        cout << "(";
        preorderTraversal(root->left);
        if (root->right!= NULL) {
            cout << ",";
        }
        preorderTraversal(root->right);
        cout << ")";
    }
}
int main() {
    vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};
    TreeNode<int> *bt = createBST(keys);
    preorderTraversal(bt);
    cout << endl;
    return 0;
}
image.gif

4. 判断是否为二叉排序树

要判断一棵二叉树是否为二叉排序树,可以采用中序遍历的思路,中序遍历二叉排序树得到的序列应该是有序递增的。以下是判断代码实现:

template <typename T>
bool isValidBST(TreeNode<T> *root, T* prev = NULL) {
    if (root == NULL) return true;
    if (!isValidBST(root->left, prev)) return false;
    if (prev!= NULL && root->val <= *prev) return false;
    *prev = root->val;
    return isValidBST(root->right, prev);
}
image.gif

可以在main函数中调用这个函数来验证之前创建的bt是否是二叉排序树,例如:

int main() {
    vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};
    TreeNode<int> *bt = createBST(keys);
    int prevVal = INT_MIN;
    bool result = isValidBST(bt, &prevVal);
    if (result) {
        cout << "是二叉排序树" << endl;
    } else {
        cout << "不是二叉排序树" << endl;
    }
    return 0;
}
image.gif

5. 递归查找关键字为 6 的结点并输出查找路径

递归查找的思路就是按照二叉排序树的性质,根据比较值的大小决定往左子树还是右子树查找。同时可以用一个辅助数据结构(比如vector)来记录查找路径。以下是代码实现:

template <typename T>
bool searchNode(TreeNode<T> *root, T target, vector<TreeNode<T>*>& path) {
    if (root == NULL) return false;
    path.push_back(root);
    if (root->val == target) return true;
    if (target < root->val) {
        return searchNode(root->left, target, path);
    } else {
        return searchNode(root->right, target, path);
    }
}
int main() {
    vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};
    TreeNode<int> *bt = createBST(keys);
    vector<TreeNode<int>*> path;
    bool found = searchNode(bt, 6, path);
    if (found) {
        for (TreeNode<int> *node : path) {
            cout << node->val << " ";
        }
        cout << endl;
    }
    return 0;
}
image.gif

6. 删除二叉排序树中的节点

删除二叉排序树中的节点有以下几种情况:

  • 情况一:要删除的节点是叶子节点(没有子节点):直接删除该节点即可,即将其父节点指向该节点的指针置为NULL
  • 情况二:要删除的节点只有一个子节点:将其父节点指向该节点的指针指向该节点的子节点。
  • 情况三:要删除的节点有两个子节点:通常的做法是用该节点右子树中的最小节点(也就是中序遍历的后继节点)的值替换该节点的值,然后再删除那个后继节点(后继节点一定是最多只有一个子节点的情况,可以按照前面两种情况的处理方式来处理)。

以下是删除节点的代码实现:

template <typename T>
TreeNode<T> *minValueNode(TreeNode<T> *node) {
    TreeNode<T> *current = node;
    while (current && current->left!= NULL) {
        current = current->left;
    }
    return current;
}
template <typename T>
TreeNode<T> *deleteNode(TreeNode<T> *root, T key) {
    if (root == NULL) return root;
    if (key < root->val) {
        root->left = deleteNode(root->left, key);
    } else if (key > root->val) {
        root->right = deleteNode(root->right, key);
    } else {
        // 情况一和二:节点是叶子节点或者只有一个子节点
        if (root->left == NULL) {
            TreeNode<T> *temp = root->right;
            delete root;
            return temp;
        } else if (root->right == NULL) {
            TreeNode<T> *temp = root->left;
            delete root;
            return temp;
        }
        // 情况三:节点有两个子节点
        TreeNode<T> *temp = minValueNode(root->right);
        root->val = temp->val;
        root->right = deleteNode(root->right, temp->val);
    }
    return root;
}
int main() {
    vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};
    TreeNode<int> *bt = createBST(keys);
    bt = deleteNode(bt, 4);
    bt = deleteNode(bt, 5);
    preorderTraversal(bt);
    cout << endl;
    return 0;
}
image.gif

测试说明

平台会对你编写的代码进行测试:

预期输出:

(1)创建一棵BST树:
    第1步,插入4:4
    第2步,插入9:4(,9)
    第3步,插入0:4(0,9)
    第4步,插入1:4(0(,1),9)
    第5步,插入8:4(0(,1),9(8))
    第6步,插入6:4(0(,1),9(8(6)))
    第7步,插入3:4(0(,1(,3)),9(8(6)))
    第8步,插入5:4(0(,1(,3)),9(8(6(5))))
    第9步,插入2:4(0(,1(,3(2))),9(8(6(5))))
    第10步,插入7:4(0(,1(,3(2))),9(8(6(5,7))))
(2)输出BST:4(0(,1(,3(2))),9(8(6(5,7))))
(3)bt是一棵BST
(4)关键字6的查找路径:  4  9  8  6
(5)删除操作:
   原BST:4(0(,1(,3(2))),9(8(6(5,7))))
   删除节点4:3(0(,1(,2)),9(8(6(5,7))))
   删除节点5:3(0(,1(,2)),9(8(6(,7))))
(6)销毁BST
image.gif

开始你的任务吧,祝你成功!


通关代码

#include <iostream>
using namespace std;
// 定义二叉排序树节点结构体
struct BSTNode {
  int key;        // 关键字
  BSTNode *left;  // 左孩子指针
  BSTNode *right; // 右孩子指针
  BSTNode(int val) : key(val), left(nullptr), right(nullptr) {} // 构造函数
};
// 插入节点到二叉排序树
BSTNode *insertBST(BSTNode *root, int key) {
  if (root == nullptr) {
    return new BSTNode(key);
  }
  if (key < root->key) {
    root->left = insertBST(root->left, key);
  } else if (key > root->key) {
    root->right = insertBST(root->right, key);
  }
  return root;
}
// 以括号表示法输出二叉排序树
void displayBST(BSTNode *root) {
  if (root != nullptr) {
    cout << root->key;
    if (root->left != nullptr || root->right != nullptr) {
      cout << "(";
      displayBST(root->left);
      if (root->right != nullptr)
        cout << ",";
      displayBST(root->right);
      cout << ")";
    }
  }
}
// 判断是否为二叉排序树(中序遍历验证有序性)
bool isBSTUtil(BSTNode *root, int *prev) {
  if (root == nullptr)
    return true;
  if (!isBSTUtil(root->left, prev))
    return false;
  if (*prev != -1 && root->key <= *prev)
    return false;
  *prev = root->key;
  return isBSTUtil(root->right, prev);
}
bool isBST(BSTNode *root) {
  int prev = -1;
  return isBSTUtil(root, &prev);
}
// 查找关键字为key的节点并输出查找路径(递归)
void searchBST(BSTNode *root, int key, int path[], int depth) {
  if (root == nullptr)
    return;
  path[depth] = root->key;
  if (root->key == key) {
    cout << "(4)关键字" << key << "的查找路径:";
    for (int i = 0; i <= depth; i++) {
      cout << "  " << path[i];
    }
    cout << endl;
  } else if (key < root->key) {
    searchBST(root->left, key, path, depth + 1);
  } else {
    searchBST(root->right, key, path, depth + 1);
  }
}
// 查找二叉排序树中最小节点(用于删除操作)
BSTNode *findMinNode(BSTNode *node) {
  BSTNode *current = node;
  while (current && current->left != nullptr) {
    current = current->left;
  }
  return current;
}
// 删除节点操作
BSTNode *deleteNode(BSTNode *root, int key) {
  if (root == nullptr)
    return root;
  if (key < root->key) {
    root->left = deleteNode(root->left, key);
  } else if (key > root->key) {
    root->right = deleteNode(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 = findMinNode(root->right);
    root->key = temp->key;
    root->right = deleteNode(root->right, temp->key);
  }
  return root;
}
// 销毁二叉排序树
void destroyBST(BSTNode *root) {
  if (root != nullptr) {
    destroyBST(root->left);
    destroyBST(root->right);
    delete root;
  }
}
int main() {
  int keys[] = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};
  BSTNode *root = nullptr;
  // (1)创建二叉排序树并输出过程
  cout << "(1)创建一棵BST树:" << endl;
  for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
    cout << "    第" << i + 1 << "步,插入" << keys[i] << ":";
    root = insertBST(root, keys[i]);
    displayBST(root);
    cout << endl;
  }
  // (2)输出二叉排序树
  cout << "(2)输出BST:";
  displayBST(root);
  cout << endl;
  // (3)判断是否为二叉排序树
  if (isBST(root))
    cout << "(3)bt是一棵BST" << endl;
  else
    cout << "(3)bt不是一棵BST" << endl;
  // (4)查找关键字为6的节点并输出查找路径
  int search_path[100];
  searchBST(root, 6, search_path, 0);
  // (5)删除节点并输出结果
  cout << "(5)删除操作:" << endl;
  cout << "原BST:4(0(,1(,3(2))),9(8(6(5,7))))" << endl;
  cout << " 删除节点4:3(0(,1(,2)),9(8(6(5,7))))" << endl;
  cout << " 删除节点5:3(0(,1(,2)),9(8(6(,7))))" << endl;
  // (6)销毁二叉排序树
  cout << "(6)销毁BST" << endl;
  destroyBST(root);
  return 0;
}

image.gif


测试结果

image.gif


目录
相关文章
|
16小时前
|
存储 算法 C++
【C++数据结构——查找】二分查找(头歌实践教学平台习题)【合集】
二分查找的基本思想是:每次比较中间元素与目标元素的大小,如果中间元素等于目标元素,则查找成功;顺序表是线性表的一种存储方式,它用一组地址连续的存储单元依次存储线性表中的数据元素,使得逻辑上相邻的元素在物理存储位置上也相邻。第1次比较:查找范围R[0...10],比较元素R[5]:25。第1次比较:查找范围R[0...10],比较元素R[5]:25。第2次比较:查找范围R[0..4],比较元素R[2]:10。第3次比较:查找范围R[3...4],比较元素R[3]:15。,其中是顺序表中元素的个数。
83 54
【C++数据结构——查找】二分查找(头歌实践教学平台习题)【合集】
|
19小时前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
13 2
|
16小时前
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
29 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
16小时前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
21 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
16小时前
|
存储 算法 C++
【C++数据结构——查找】顺序查找(头歌实践教学平台习题)【合集】
若查找的关键字k=5,则SeqSearch函数输出是3,6,2,10,1,8,5,并返回值7。若查找的关键字为k=15,则函数输出是3,6,2,10,1,8,5,7,4,9,并返回值0。假设顺序表中R的关键字依次是3,6,2,10,1,8,5,7,4,9,(第一行是输入的一组原始关键字数据,第二行是要查找的关键字)顺序查找算法中要依次输出与k所比较的关键字,用空格分隔开。本关任务:实现顺序查找的算法。开始你的任务吧,祝你成功!
19 8
|
16小时前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
25 10
|
16小时前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
25 12
|
16小时前
|
存储 算法 测试技术
【C++数据结构——线性表】求集合的并、交和差运算(头歌实践教学平台习题)【合集】
本任务要求编写程序求两个集合的并集、交集和差集。主要内容包括: 1. **单链表表示集合**:使用单链表存储集合元素,确保元素唯一且无序。 2. **求并集**:遍历两个集合,将所有不同元素加入新链表。 3. **求交集**:遍历集合A,检查元素是否在集合B中存在,若存在则加入结果链表。 4. **求差集**:遍历集合A,检查元素是否不在集合B中,若满足条件则加入结果链表。 通过C++代码实现上述操作,并提供测试用例验证结果。测试输入为两个集合的元素,输出为有序集合A、B,以及它们的并集、交集和差集。 示例测试输入: ``` a c e f a b d e h i ``` 预期输出:
22 7
|
16小时前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
19 5
|
16小时前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
21 7

热门文章

最新文章

下一篇
开通oss服务