Program work 7. 用数组实现一棵二叉搜索树的建立与节点删除操作

本文详细介绍了如何构建二叉搜索树,并通过递归版本实现了删除操作。包括了数组实现、空间复杂度分析、删除操作的时间复杂度、重建树的方法以及删除后的输出展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:

        输入: 2, 3, 1, 4, 5. 生成一颗二叉搜索树应:  2 1 3 x x x 4 x x x x x x x 5 (x代表该节点为空)

        输入指定删除位置, 并展示删除后的二叉搜索树.

        如: 删除5, 该位置无节点, 弹出节点为空的信息. 例如删除6, 则删除后的二叉搜索树为:  2 1 3 x x x 5 

        每次删除后, 优先找其左子树的最大值进行替换, 若无左子树则找其右子树的最小值进行替换.

        这里只给出递归版本, 不给出迭代版本

Program environment:

        Operation System: Ubuntu 14.04

        Ide: Eclipse

        Compiler: g++

        Language: c++

Requirements: 

        Deletion from the binary search tree should be O(1) in space complexity. Two versions: one is iterative version, the other is recursive version.

Ideas:

To achieve the O(1) space complexity, it’s natural to coming up with the array’s implementation.


Facing with this problem, the first question is the length of the array as the infinite input not until -1 entered. Because is a binary tree, but not a AVL tree, the worst case occurs when input is like: 1, 2, 3, 4, 5... in increasing order which will create a right skew binary search tree. If the input has n nodes, then the array length should be 2^n.


From the properties of binary search tree, we know there is no same element in the tree. But requirement doesn’t state clearly that all nodes are different, so there’s a trap here.


The built binary search tree must meet the property that any node must be greater than any node of its left subtree and smaller than any node of its right subtree. Following this rule, select the first node as tree’s root, for each node, then do the comparison until a no occupied index found.


Deletion operation is only O(1). But before the deletion we should find the node(denoted as d) which is ready to take place of the deleting node. The finding operation is O(h), h is the height of the tree. The finding is also based on the comparison obtaining the rule: priority is finding the largest node of d’s left subtree, if d has no left subtree then find the smallest node of d’s right subtree, else d is the leaf node whick can be directly deleted. The finding function has two version, one is iterative version the other is recursive version.


Rebuilding d’s subtrees is the hardest part of this assignment, i think. To implement the rebuilding, i choose a queue to store the d’s descendants. While queue is used for level traversal. The procedure is shown below:


We first replace the red node which client asks to be deleted with the green. Then we move d’s subtree upward level by level.

Input & Output:

        Input: a. a list of nodes. (-1 to terminate)

                   b. the index of executing deletion.

        Output: a. the binary search tree

                      b. the binary search tree after each deletion

//============================================================================
// Name        : recursive_version.cpp
// Author      : Reid Chan
// Version     :
// Copyright   : Your copyright notice
//============================================================================

#include <iostream>
#include <queue>
#include <cmath>

using namespace std;

#define null -1		// Used for representing the null tree node
int end = -1;			// Used for recording the index of the last node
int size;					// Used for recording the number of nodes in the tree

/**
 * Used to build the binary search tree.
 * t: the tree array
 * q: the input nodes stored in a queue.
 */
void buildTree(int *t, queue<int> q) {
	t[1] = q.front();			// the first node will be root.
	q.pop();
	int child, parent;
	while (!q.empty()) {
		/* get the node and locate it at the appropriate index */
		child = q.front();
		parent = 1;
		while (t[parent] != null) {
			if (child > t[parent]) {
				parent = 2 * parent + 1;
			} else if (child < t[parent]) {
				parent = 2 * parent;
			} else {
				/**
				 * if there're nodes that have the same element, only the first will be kept
				 * the number of the nodes should minus one every time occurs
				 */
				size--;
				break;
			}
		}
		t[parent] = child;
		if (parent > end) { end = parent; }	// record the index of last node
		q.pop();
	}
}

/**
 * it's invoked after deletion completed.
 * it's for placing the nodes to the appropriate index respectively.
 * a queue is used here, it's for level traversal a technique applied when rebuilding
 */
void rebuild(int *t, int i, int flag)
{
	queue<int> que;
	if (i * 2 <= end && t[i * 2] != null) { que.push(i * 2); }
	if (i * 2 + 1 <= end && t[i * 2 + 1] != null) { que.push(i * 2 + 1); }
	t[i] = -1;
	int x;
	while (!que.empty()) {
		// get the current node's index
		x = que.front();
		// check if the current node has children,
		// push the children in the queue if exists.
		if (t[x * 2] != null && x * 2 <= end) { que.push(x * 2); }
		if (t[x * 2 + 1] != null && x * 2 + 1 <= end) { que.push(x * 2 + 1); }
		// replace the parent node with the current node.
		if (flag == 1) { t[(x + 1) / 2] = t[x]; }
		else { t[(x - 1) / 2] = t[x]; }
		// set the current node as null, and move to the next node
		t[x] = null;
		que.pop();
	}
}

/**
 * function for keeping track of the last node of the tree
 */
void getEnd(int *t)
{
	for (int i = end; i >= 1; i--) {
		if (t[i] != null) {
			end = i;
			break;
		}
	}
}

void recursiveFind(int *t, int &i, int f) {
	if (t[i] == null) {
		i = (f ? (i - 1) / 2 : i / 2);
		return;
	}
	if (f == 1) {
		recursiveFind(t, (i = i * 2 + 1), 1);
	} else {
		recursiveFind(t, (i = i * 2), 0);
	}
}

/**
 * delete the node at index i, then rebuild its subtrees.
 */
void deleteNode(int *t, int i) {
	int flag;
	int p = i;
	/********* recursive version *********/
	/**
	 * 1. if left subtree is exist. find the largest node of the left subtree,
	 * 		then replace the deleted node with it.
	 */
	if (t[p * 2] != null) {
		p *= 2;
		flag = 1;
		recursiveFind(t, p, flag);
	}
	/**
	 * 2. if left subtree is empty, and right subtree is exist.
	 * 		find the smallest node of the right subtree,
	 * 		then replace the deleted node with it.
	 */
	else if (t[p * 2 + 1] != null) {
		p = p * 2 + 1;
		flag = 0;
		recursiveFind(t, p, flag);
	}
	t[i] = t[p];					// replacement operation
	rebuild(t, p, flag);  // rebuild its subtree.
	getEnd(t);
}

/**
 * printOut the whole tree
 */
void printOut(int *t) {
	cout << "Binary search tree is:" << endl;
	for (int i = 1; i <= end; ++i) {
		if (t[i] == null) {
			cout << 'x' << ' ';
			continue;
		}
		cout << t[i] << ' ';
	}
	cout << endl;
}

int main() {
	cout << "Please input(-1 as an end): ";
	queue<int> nodes;					// used to store input nodes. FIFO
	int num;
	while (cin >> num && num != null) {
		nodes.push(num);
	}
	size = nodes.size();			// get the number of nodes(notice that possibly some will be repeated)
	int sz = pow(2, size);		// the worst case is right-skewed tree, thus at least require 2^n space.
	int *tree = new int[sz];	// initialization the tree nodes as -1(null)
	for (int i = 0; i < sz; ++i) {
		tree[i] = -1;
	}

	buildTree(tree, nodes);
	printOut(tree);

	int del;
	cout << "Delete element at index(-1 to terminate deletion): ";
	/* to user the index begins at 0, but in implementation it begins at 1
	 * that's why a plus one occurs
	 */
	while (cin >> del && del != -1) {
		if (size == 0) {
			cout << "Error: The tree is empty~" << endl;
			return 0;
		}
		if (del + 1> end) {
			cout << "Error: It's out of range!" << endl;
		} else if (tree[del + 1] == null) {
			cout << "Warning: no element at index " << del << "."<< endl;
		} else {
			deleteNode(tree, del + 1);
			size--;
			printOut(tree);
		}
		cout << "Delete element at index(-1 to terminate deletion): ";
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值