静态列表BST的简单功能实现

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树

当然首先要初始化数组,这里给出两种方法

  1. 提供数组
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]);
    }
}
  1. 提供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为根的子树上(准确来说是覆盖)递归方法和中序遍历有点像

void SeqBST::move(int curr, int ptr) {

    if (tree_list[curr] == DEFAULT_VALUE) {
        return;
    }
    else {
        tree_list[ptr] = tree_list[curr];
        tree_list[curr] = DEFAULT_VALUE;
    }
    move(rightIndex(curr), rightIndex(ptr));
    move(leftIndex(curr), leftIndex(ptr));
}

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;
}
posted @ 2020-12-19 14:28  Mezzベ  阅读(167)  评论(0)    收藏  举报