BST树的创建方法其实在网上随便一搜就能搜到好多的,不过网上的BST树基本都是使用链表实现。其实使用静态列表个人觉得没什么用处,不过还是写一下来锻炼自己对数组的一些操作。
1,存储方式
当然使用数组来存了。我先定义了两个常数
MAXSIZE
数组的最大值DEFAULT_VALUE
未使用某结点时将其值设为该默认值
类中的数组名我起为tree_list
2,创建方法
1)获得孩子坐标
因为数组的下标从0开始,所以经简单推导可以得到
int SeqBST::leftIndex(int index) {
return 2 * index + 1;
}
int SeqBST::rightIndex(int index) {
return 2 * index + 2;
}
2)父亲结点
父亲结点其实也可以通过下标运算得到
int SeqBST::parentIndex(int index) {
return (index - 1) / 2;
}
3)定义添加节点函数
方法差不多,静态数组是通过下标寻址
void SeqBST::addValue(int val) {
// 如果未创建树则新建根结点并赋值
if (tree_list[0] == DEFAULT_VALUE) {
tree_list[0] = val;
return;
}
// 通过curr找到数值添加位置
int curr = 0;
while (true) {
// 如果curr处的值大于val,则说明val应添加在curr和左孩子上
if (tree_list[curr] > val) {
int left = leftIndex(curr);
// 左孩子不为空则在其左孩子处继续寻找位置
if (tree_list[left] != DEFAULT_VALUE) {
curr = left;
continue;
}
// 左孩子为空则在该处插入val并退出循环
else {
tree_list[left] = val;
break;
}
}
// 和上面类似
else if (tree_list[curr] < val) {
int right = rightIndex(curr);
if (tree_list[right] != DEFAULT_VALUE) {
curr = right;
continue;
}
else {
tree_list[right] = val;
break;
}
}
}
}
4)初始化BST树
当然首先要初始化数组,这里给出两种方法
- 提供数组
SeqBST::SeqBST(int* arr, int size) {
tree_list = new int[MAXSIZE];
for (int i = 0; i < MAXSIZE; i++) {
tree_list[i] = DEFAULT_VALUE;
}
this->size = size;
for (int i = 0; i < size; i++) {
this->addValue(arr[i]);
}
}
- 提供vector
SeqBST::SeqBST(std::vector<int> vec) {
tree_list = new int[MAXSIZE];
for (int i = 0; i < MAXSIZE; i++) {
tree_list[i] = DEFAULT_VALUE;
}
this->size = vec.size();
for (auto iter : vec) {
this->addValue(iter);
}
}
3,一些方法
1)中序遍历
我用的递归,不多说上代码
void SeqBST::inOrder() {
inOrder(0);
std::cout << std::endl;
}
void SeqBST::inOrder(int index) {
if (tree_list[index] == DEFAULT_VALUE) {
return;
}
inOrder(leftIndex(index));
std::cout << tree_list[index] << " ";
inOrder(rightIndex(index));
}
2)删除结点
静态列表删除结点挺让人头疼的,
其实删除结点后最重要的时如何处理其左右两个子树,我先定义了一个move
函数,其作用是将以curr为根的子树移到以ptr为根的子树上(准确来说是覆盖)我使用层序遍历来移动子树,不管curr的子树是不是空的都复制到ptr的子树下,如果连续多个移动的结点值都为DEFAULT_VALUE则说明子树全部移动完毕
void SeqBST::move(int curr, int ptr) {
// 使用层序遍历来移动子树来确保子树能够全部转移
std::queue<int> curr_queue;
std::queue<int> ptr_queue;
curr_queue.push(curr);
ptr_queue.push(ptr);
int flag = 0;
int depth_flag = 0;
while (!curr_queue.empty()) {
depth_flag += 2;
if (flag > sqrt(depth_flag)) {
break;
}
int cur_ = curr_queue.front();
int ptr_ = ptr_queue.front();
if (tree_list[cur_] != DEFAULT_VALUE || tree_list[ptr_] != DEFAULT_VALUE) {
flag = 0;
}
if (tree_list[cur_] == DEFAULT_VALUE && tree_list[ptr_] == DEFAULT_VALUE) {
flag++;
}
curr_queue.push(rightIndex(cur_));
curr_queue.push(leftIndex(cur_));
ptr_queue.push(rightIndex(ptr_));
ptr_queue.push(leftIndex(ptr_));
tree_list[ptr_] = tree_list[cur_];
tree_list[cur_] = DEFAULT_VALUE;
curr_queue.pop();
ptr_queue.pop();
}
ptr原有的子树会被curr的子树覆盖
然后就来删除结点,思路和链式存储其实有点像
bool SeqBST::deleteNode(int val) {
int ptr = findNode(val);
// 判断是否找到该结点
if (ptr == -1) { return false; }
// 如果ptr为叶子结点直接删除
if (isLeaf(ptr)) {
tree_list[ptr] = DEFAULT_VALUE;
return true;
}
// 如果只有左孩子
else if (tree_list[rightIndex(ptr)] == DEFAULT_VALUE) {
this->move(leftIndex(ptr), ptr);
return true;
}
// 如果只有右孩子
else if (tree_list[leftIndex(ptr)] == DEFAULT_VALUE) {
this->move(rightIndex(ptr), ptr);
return true;
}
// 既有左孩子又有右孩子
else {
int curr = rightIndex(ptr);
while (tree_list[curr] != DEFAULT_VALUE) {
curr = leftIndex(curr);
}
this->move(leftIndex(ptr), curr);
this->move(rightIndex(ptr), ptr);
}
return true;
}