Free memory after removing

a node from a LinkedList or TreeNode.
pull/200/head
Yudong Jin 2 years ago
parent 6b02449f22
commit 410c5d6b62

@ -21,6 +21,8 @@ void remove(ListNode* n0) {
ListNode* P = n0->next;
ListNode* n1 = P->next;
n0->next = n1;
// 释放内存
delete P;
}
/* 访问链表中索引为 index 的结点 */

@ -50,7 +50,10 @@ public:
int poll() {
int num = peek();
// 删除头结点
ListNode *tmp = front;
front = front->next;
// 释放内存
delete tmp;
queSize--;
return num;
}

@ -39,7 +39,10 @@ public:
/* 出栈 */
int pop() {
int num = top();
ListNode *tmp = stackTop;
stackTop = stackTop->next;
// 释放内存
delete tmp;
stkSize--;
return num;
}

@ -96,11 +96,13 @@ public:
// 删除结点 cur
if (pre->left == cur) pre->left = child;
else pre->right = child;
// 释放内存
delete cur;
}
// 子结点数量 = 2
else {
// 获取中序遍历中 cur 的下一个结点
TreeNode* nex = min(cur->right);
TreeNode* nex = getInOrderNext(cur->right);
int tmp = nex->val;
// 递归删除结点 nex
remove(nex->val);
@ -110,8 +112,8 @@ public:
return cur;
}
/* 获取最小结点 */
TreeNode* min(TreeNode* root) {
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
TreeNode* getInOrderNext(TreeNode* root) {
if (root == nullptr) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (root->left != nullptr) {

@ -33,6 +33,7 @@ int main() {
PrintUtil::printTree(n1);
// 删除结点 P
n1->left = n2;
delete P; // 释放内存
cout << endl << "删除结点 P 后\n" << endl;
PrintUtil::printTree(n1);

@ -162,7 +162,7 @@ namespace hello_algo.chapter_tree
else
{
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点
TreeNode? temp = minNode(node.right);
TreeNode? temp = getInOrderNext(node.right);
node.right = removeHelper(node.right, temp.val);
node.val = temp.val;
}
@ -174,8 +174,8 @@ namespace hello_algo.chapter_tree
return node;
}
/* 获取最小结点 */
private TreeNode? minNode(TreeNode? node)
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
private TreeNode? getInOrderNext(TreeNode? node)
{
if (node == null) return node;
// 循环访问左子结点,直到叶结点时为最小结点,跳出

@ -125,7 +125,7 @@ namespace hello_algo.chapter_tree
else
{
// 获取中序遍历中 cur 的下一个结点
TreeNode? nex = min(cur.right);
TreeNode? nex = getInOrderNext(cur.right);
if (nex != null)
{
int tmp = nex.val;
@ -138,8 +138,8 @@ namespace hello_algo.chapter_tree
return cur;
}
/* 获取最小结点 */
private TreeNode? min(TreeNode? root)
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
private TreeNode? getInOrderNext(TreeNode? root)
{
if (root == null) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出

@ -23,13 +23,13 @@ func NewBinarySearchTree(nums []int) *BinarySearchTree {
}
}
// GetRoot Get the root node of binary search tree
/* 获取根结点 */
func (bst *BinarySearchTree) GetRoot() *TreeNode {
return bst.root
}
// GetMin Get node with the min value
func (bst *BinarySearchTree) GetMin(node *TreeNode) *TreeNode {
/* 获取中序遍历的下一个结点 */
func (bst *BinarySearchTree) GetInOrderNext(node *TreeNode) *TreeNode {
if node == nil {
return node
}
@ -40,19 +40,6 @@ func (bst *BinarySearchTree) GetMin(node *TreeNode) *TreeNode {
return node
}
// GetInorderNext Get node inorder next
func (bst *BinarySearchTree) GetInorderNext(node *TreeNode) *TreeNode {
if node == nil || node.Right == nil {
return node
}
node = node.Right
// 循环访问左子结点,直到叶结点时为最小结点,跳出
for node.Left != nil {
node = node.Left
}
return node
}
/* 查找结点 */
func (bst *BinarySearchTree) Search(num int) *TreeNode {
node := bst.root
@ -149,7 +136,7 @@ func (bst *BinarySearchTree) Remove(num int) *TreeNode {
// 子结点数为 2
} else {
// 获取中序遍历中待删除结点 cur 的下一个结点
next := bst.GetInorderNext(cur)
next := bst.GetInOrderNext(cur)
temp := next.Val
// 递归删除结点 next
bst.Remove(next.Val)

@ -12,33 +12,30 @@ import (
func TestBinarySearchTree(t *testing.T) {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
bst := NewBinarySearchTree(nums)
fmt.Println("初始化的二叉树为:")
fmt.Println("\n初始化的二叉树为:")
bst.Print()
// 获取根结点
node := bst.GetRoot()
fmt.Println("二叉树的根结点为:", node.Val)
// 获取最小的结点
node = bst.GetMin(bst.GetRoot())
fmt.Println("二叉树的最小结点为:", node.Val)
fmt.Println("\n二叉树的根结点为:", node.Val)
// 查找结点
node = bst.Search(5)
fmt.Println("查找到的结点对象为", node, ",结点值 =", node.Val)
fmt.Println("\n查找到的结点对象为", node, ",结点值 =", node.Val)
// 插入结点
node = bst.Insert(16)
fmt.Println("插入结点后 16 的二叉树为:")
fmt.Println("\n插入结点后 16 的二叉树为:")
bst.Print()
// 删除结点
bst.Remove(1)
fmt.Println("删除结点 1 后的二叉树为:")
fmt.Println("\n删除结点 1 后的二叉树为:")
bst.Print()
bst.Remove(2)
fmt.Println("删除结点 2 后的二叉树为:")
fmt.Println("\n删除结点 2 后的二叉树为:")
bst.Print()
bst.Remove(4)
fmt.Println("删除结点 4 后的二叉树为:")
fmt.Println("\n删除结点 4 后的二叉树为:")
bst.Print()
}

@ -138,7 +138,7 @@ class AVLTree {
node = child;
} else {
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点
TreeNode temp = minNode(node.right);
TreeNode temp = getInOrderNext(node.right);
node.right = removeHelper(node.right, temp.val);
node.val = temp.val;
}
@ -150,8 +150,8 @@ class AVLTree {
return node;
}
/* 获取最小结点 */
private TreeNode minNode(TreeNode node) {
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
private TreeNode getInOrderNext(TreeNode node) {
if (node == null) return node;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (node.left != null) {

@ -101,7 +101,7 @@ class BinarySearchTree {
// 子结点数量 = 2
else {
// 获取中序遍历中 cur 的下一个结点
TreeNode nex = min(cur.right);
TreeNode nex = getInOrderNext(cur.right);
int tmp = nex.val;
// 递归删除结点 nex
remove(nex.val);
@ -111,8 +111,8 @@ class BinarySearchTree {
return cur;
}
/* 获取最小结点 */
public TreeNode min(TreeNode root) {
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
public TreeNode getInOrderNext(TreeNode root) {
if (root == null) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (root.left != null) {

@ -98,7 +98,7 @@ function remove(num) {
// 子结点数量 = 2
else {
// 获取中序遍历中 cur 的下一个结点
let nex = min(cur.right);
let nex = getInOrderNext(cur.right);
let tmp = nex.val;
// 递归删除结点 nex
remove(nex.val);
@ -108,8 +108,8 @@ function remove(num) {
return cur;
}
/* 获取最小结点 */
function min(root) {
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
function getInOrderNext(root) {
if (root === null) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (root.left !== null) {

@ -132,7 +132,7 @@ class AVLTree:
else:
node = child
else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点
temp = self.__min_node(node.right)
temp = self.__get_inorder_next(node.right)
node.right = self.__remove_helper(node.right, temp.val)
node.val = temp.val
# 更新结点高度
@ -140,8 +140,8 @@ class AVLTree:
# 2. 执行旋转操作,使该子树重新恢复平衡
return self.__rotate(node)
""" 获取最小结点 """
def __min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]:
""" 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) """
def __get_inorder_next(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]:
if node is None:
return None
# 循环访问左子结点,直到叶结点时为最小结点,跳出

@ -117,7 +117,7 @@ class BinarySearchTree:
# 子结点数量 = 2
else:
# 获取中序遍历中 cur 的下一个结点
nex = self.min(cur.right)
nex = self.get_inorder_next(cur.right)
tmp = nex.val
# 递归删除结点 nex
self.remove(nex.val)
@ -125,11 +125,10 @@ class BinarySearchTree:
cur.val = tmp
return cur
""" 获取最小结点 """
def min(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]:
""" 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) """
def get_inorder_next(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]:
if root is None:
return root
# 循环访问左子结点,直到叶结点时为最小结点,跳出
while root.left is not None:
root = root.left

@ -120,7 +120,7 @@ function remove(num: number): TreeNode | null {
// 子结点数量 = 2
else {
// 获取中序遍历中 cur 的下一个结点
let next = min(cur.right);
let next = getInOrderNext(cur.right);
let tmp = next!.val;
// 递归删除结点 nex
remove(next!.val);
@ -130,8 +130,8 @@ function remove(num: number): TreeNode | null {
return cur;
}
/* 获取最小结点 */
function min(root: TreeNode | null): TreeNode | null {
/* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */
function getInOrderNext(root: TreeNode | null): TreeNode | null {
if (root === null) {
return null;
}

@ -293,6 +293,8 @@ comments: true
ListNode* P = n0->next;
ListNode* n1 = P->next;
n0->next = n1;
// 释放内存
delete P;
}
```

@ -331,7 +331,10 @@ comments: true
int poll() {
int num = peek();
// 删除头结点
ListNode *tmp = front;
front = front->next;
// 释放内存
delete tmp;
queSize--;
return num;
}

@ -311,7 +311,10 @@ comments: true
/* 出栈 */
int pop() {
int num = top();
ListNode *tmp = stackTop;
stackTop = stackTop->next;
// 释放内存
delete tmp;
stkSize--;
return num;
}

@ -772,7 +772,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作其可 **在不影
node = child;
} else {
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点
TreeNode temp = minNode(node.right);
TreeNode temp = getInOrderNext(node.right);
node.right = removeHelper(node.right, temp.val);
node.val = temp.val;
}
@ -783,16 +783,6 @@ AVL 树的独特之处在于「旋转 Rotation」的操作其可 **在不影
// 返回子树的根节点
return node;
}
/* 获取最小结点 */
TreeNode minNode(TreeNode node) {
if (node == null) return node;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (node.left != null) {
node = node.left;
}
return node;
}
```
=== "C++"
@ -828,22 +818,13 @@ AVL 树的独特之处在于「旋转 Rotation」的操作其可 **在不影
else:
node = child
else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点
temp = self.min_node(node.right)
temp = self.__get_inorder_next(node.right)
node.right = self.__remove_helper(node.right, temp.val)
node.val = temp.val
# 更新结点高度
self.__update_height(node)
# 2. 执行旋转操作,使该子树重新恢复平衡
return self.__rotate(node)
""" 获取最小结点 """
def min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]:
if node is None:
return None
# 循环访问左子结点,直到叶结点时为最小结点,跳出
while node.left is not None:
node = node.left
return node
```
=== "Go"
@ -904,7 +885,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作其可 **在不影
else
{
// 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点
TreeNode? temp = minNode(node.right);
TreeNode? temp = getInOrderNext(node.right);
node.right = removeHelper(node.right, temp.val);
node.val = temp.val;
}
@ -915,18 +896,6 @@ AVL 树的独特之处在于「旋转 Rotation」的操作其可 **在不影
// 返回子树的根节点
return node;
}
/* 获取最小结点 */
private TreeNode? minNode(TreeNode? node)
{
if (node == null) return node;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (node.left != null)
{
node = node.left;
}
return node;
}
```
### 查找结点

@ -445,19 +445,15 @@ comments: true
3. 使用 `nex` 替换待删除结点;
=== "Step 1"
![bst_remove_case3_1](binary_search_tree.assets/bst_remove_case3_1.png)
=== "Step 2"
![bst_remove_case3_2](binary_search_tree.assets/bst_remove_case3_2.png)
=== "Step 3"
![bst_remove_case3_3](binary_search_tree.assets/bst_remove_case3_3.png)
=== "Step 4"
![bst_remove_case3_4](binary_search_tree.assets/bst_remove_case3_4.png)
删除结点操作也使用 $O(\log n)$ 时间,其中查找待删除结点 $O(\log n)$ ,获取中序遍历后继结点 $O(\log n)$ 。
@ -489,11 +485,13 @@ comments: true
// 删除结点 cur
if (pre.left == cur) pre.left = child;
else pre.right = child;
// 释放内存
delete cur;
}
// 子结点数量 = 2
else {
// 获取中序遍历中 cur 的下一个结点
TreeNode nex = min(cur.right);
TreeNode nex = getInOrderNext(cur.right);
int tmp = nex.val;
// 递归删除结点 nex
remove(nex.val);
@ -502,15 +500,6 @@ comments: true
}
return cur;
}
/* 获取最小结点 */
TreeNode min(TreeNode root) {
if (root == null) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (root.left != null) {
root = root.left;
}
return root;
}
```
=== "C++"
@ -544,7 +533,7 @@ comments: true
// 子结点数量 = 2
else {
// 获取中序遍历中 cur 的下一个结点
TreeNode* nex = min(cur->right);
TreeNode* nex = getInOrderNext(cur->right);
int tmp = nex->val;
// 递归删除结点 nex
remove(nex->val);
@ -553,15 +542,6 @@ comments: true
}
return cur;
}
/* 获取最小结点 */
TreeNode* min(TreeNode* root) {
if (root == nullptr) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (root->left != nullptr) {
root = root->left;
}
return root;
}
```
=== "Python"
@ -604,23 +584,13 @@ comments: true
# 子结点数量 = 2
else:
# 获取中序遍历中 cur 的下一个结点
nex = self.min(cur.right)
nex = self.get_inorder_next(cur.right)
tmp = nex.val
# 递归删除结点 nex
self.remove(nex.val)
# 将 nex 的值复制给 cur
cur.val = tmp
return cur
""" 获取最小结点 """
def min(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]:
if root is None:
return root
# 循环访问左子结点,直到叶结点时为最小结点,跳出
while root.left is not None:
root = root.left
return root
```
=== "Go"
@ -671,7 +641,7 @@ comments: true
// 子结点数为 2
} else {
// 获取中序遍历中待删除结点 cur 的下一个结点
next := bst.GetInorderNext(cur)
next := bst.GetInOrderNext(cur)
temp := next.Val
// 递归删除结点 next
bst.Remove(next.Val)
@ -713,7 +683,7 @@ comments: true
// 子结点数量 = 2
else {
// 获取中序遍历中 cur 的下一个结点
let nex = min(cur.right);
let nex = getInOrderNext(cur.right);
let tmp = nex.val;
// 递归删除结点 nex
remove(nex.val);
@ -766,7 +736,7 @@ comments: true
// 子结点数量 = 2
else {
// 获取中序遍历中 cur 的下一个结点
let next = min(cur.right);
let next = getInOrderNext(cur.right);
let tmp = next!.val;
// 递归删除结点 nex
remove(next!.val);
@ -824,7 +794,7 @@ comments: true
else
{
// 获取中序遍历中 cur 的下一个结点
TreeNode? nex = min(cur.right);
TreeNode? nex = getInOrderNext(cur.right);
if (nex != null)
{
int tmp = nex.val;
@ -836,18 +806,6 @@ comments: true
}
return cur;
}
/* 获取最小结点 */
TreeNode? min(TreeNode? root)
{
if (root == null) return root;
// 循环访问左子结点,直到叶结点时为最小结点,跳出
while (root.left != null)
{
root = root.left;
}
return root;
}
```
## 二叉搜索树的优势

Loading…
Cancel
Save