二叉排序树(Binary Search Tree,简称BST),是一种特殊的二叉树,它具有以下性质:
每个节点都有一个键(Key)和两个子节点,分别称为左子节点和右子节点。
左子节点的键小于其父节点的键,右子节点的键大于其父节点的键。
对每个节点,其左子树和右子树也都是二叉排序树。
当涉及到二叉排序树的插入操作时,我们通常可以使用递归和非递归两种方式来实现。下面将为你详细介绍这两种插入方法的差异,并提供代码示例。
非递归插入
非递归插入是通过迭代的方式实现的,使用循环来遍历树并找到合适的位置进行插入。具体步骤如下:
1.如果树为空,则创建一个新结点作为根结点。
2.否则,从根结点开始,与待插入结点的值进行比较。
· 如果待插入值小于当前结点的值,则进入左子树。
· 如果待插入值大于当前结点的值,则进入右子树。
· 如果待插入值等于当前结点的值,则不进行插入操作(可以根据需要进行处理)。
3.重复步骤2,直到找到一个空位置。
4.在空位置创建一个新结点,将待插入值赋给该结点。
下面是一个示例代码:
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int value) : val(value), left(nullptr), right(nullptr) {}
};
void insertNode(TreeNode*& root, int value) {
TreeNode* newNode = new TreeNode(value);
if (root == nullptr) {
root = newNode;
return;
}
TreeNode* curr = root;
TreeNode* parent = nullptr;
while (curr != nullptr) {
parent = curr;
if (value < curr->val) {
curr = curr->left;
} else if (value > curr->val) {
curr = curr->right;
} else {
// 处理结点值相等的情况
return;
}
}
if (value < parent->val) {
parent->left = newNode;
} else {
parent->right = newNode;
}
}
递归插入
递归插入是通过函数的递归调用实现的,每次递归都会判断当前结点是否为空,从而决定是向左子树还是右子树递归。具体步骤如下:
1.如果树为空,则创建一个新结点作为根结点。
2.否则,与当前结点的值进行比较。
· 如果待插入值小于当前结点的值,则递归调用插入函数,传入当前结点的左子结点。
· 如果待插入值大于当前结点的值,则递归调用插入函数,传入当前结点的右子结点。
· 如果待插入值等于当前结点的值,则不进行插入操作(可以根据需要进行处理)。
3.在递归的最底层,创建一个新结点,将待插入值赋给该结点,并将该结点作为当前结点的子结点。
下面是一个示例代码:
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int value) : val(value), left(nullptr), right(nullptr) {}
};
void insertNode(TreeNode*& root, int value) {
if (root == nullptr) {
root = new TreeNode(value);
return;
}
if (value < root->val) {
insertNode(root->left, value);
} else if (value > root->val) {
insertNode(root->right, value);
} else {
// 处理结点值相等的情况
return;
}
}
递归与非递归的差异
1.实现方式:递归方式通过函数栈实现,而非递归方式通过循环实现。
2.代码简洁度:递归方式通常更简洁,代码更容易理解;非递归方式需要更多的控制逻辑,但更灵活。
3.性能:递归方式可能产生更多的函数调用开销,而非递归方式通过迭代实现,性能可能更好。