二叉检索树的实现——增删改查、读取命令文件、将结果写入新文件

看这篇文章前的知识储备

链接: 二叉树的性质和分类
链接: 二叉检索树的概念 、insert方法的图解、实现、时间代价分析
链接: 二叉检索树的search、remove方法的图解、实现、时间代价分析

1、中序遍历及中序遍历写进文件的区别

两者思路一致,将二叉树分为三部分:左子树,根结点,右子树。对左子树,右子树递归遍历。

(1)写入数组:

在这里插入图片描述

(2)写入文件

需要借助两个函数,目的:在传参时不需要手动重复传入二叉树根结点

第一个函数只需要传入输出文件名称即可(打开关闭文件,写入文件)
第二个函数具体实现写入文件

在这里插入图片描述
在这里插入图片描述

2、处理命令

为方便用户进行增删改查
将增删改查的命令符号分别定义为 + - = ?
具体实现如下
在这里插入图片描述

3、utf-8 和 gbk 编码的区别

UTF-8和GBK是两种不同的字符编码方式,它们之间存在一些显著的差异:

  • 字符集范围
    GBK编码主要用于支持中文字符和日韩字符,而UTF-8编码则支持全球范围内的字符。这意味着,如果需要处理多种语言字符,UTF-8将是一个更好的选择。
  • 编码方式
    GBK编码采用双字节编码,即不论中、英文字符均使用双字节来表示。而UTF-8编码则采用变长编码,一个字符的编码长度可为1~4个字节,甚至更长。这种变长编码方式使得UTF-8编码能够根据字符的实际长度来分配存储空间,因此在存储中占用的空间相对较小。
  • 兼容性
    GBK编码在国内应用广泛,但在国际化应用上可能受到限制。而UTF-8编码则具有更好的国际化兼容性,可以在各国各种支持UTF-8字符集的浏览器上显示,无需额外下载语言支持包。
  • 存储空间大小
    由于GBK编码每个字符固定占用2个字节,因此在存储中占用的空间相对较大。而UTF-8编码采用变长编码,可以根据需要分配存储空间,因此在存储中占用的空间相对较小。

综上所述,UTF-8和GBK在字符集范围、编码方式、兼容性和存储空间大小等方面存在显著差异。选择哪种编码方式取决于具体的应用场景和需求。在处理多种语言字符或需要国际化应用的场合,UTF-8编码通常更为合适;而在主要处理中文字符的场合,GBK编码可能更为常用。

(1)注意

在读取写入文件时,最好表明编码方式,防止出现UnicodeDecodeError错误
在这里插入图片描述

(2)判断文件的编码类型

在这里插入图片描述

import chardet

# 打开文件并读取一部分内容
with open('name of your file', 'rb') as f:
    rawdata = f.read(100)  # 读取前100个字节

# 使用chardet检测编码
result = chardet.detect(rawdata)
print(result)
encoding = result['encoding']

print(f"Detected encoding: {encoding}")

4、全部代码理解

(1)前期准备——Elem()、BinNode()

在这里插入图片描述

(2)查——search

在这里插入图片描述

(3)改——update

在这里插入图片描述

(4)增——insert

在这里插入图片描述

(5)删——remove

在这里插入图片描述

(6)其他方法

在这里插入图片描述

(7)读取命令

在这里插入图片描述

(8)具体命令处理

在这里插入图片描述

(8)实例

在这里插入图片描述

(9)结果

命令文件(部分)

在这里插入图片描述

运行结果(部分)

在这里插入图片描述

5、全部代码

class Elem():
    def __init__(self,val):
        if val is not None:#把要插入的元素提取出来
            self._key = val[1:-1].strip().split(',')[0]
            self._value= val[1:-1].strip().split(',')[1]
        else:
            self._key=None

    def key(self):#获取key()
        return self._key

    def value(self):
        return self._value

    def set_key(self, key):
        self._key = key

    def set_value(self, value):
        self._value = value

class BinNode:
    def __init__(self, val):
        self.left = None
        self.right = None
        self.val = val

class BST():
    def __init__(self):
        self.root=None

    def search(self,key):
        return self.search_help(self.root, key)

    def search_help(self,root,key):
        if root is None:
            return None
        it=root.val
        if it.key()>key:
            return self.search_help(root.left,key)
        elif it.key()<key:
            return self.search_help(root.right,key)
        return it.value()

    def search_node(self, root, key):
        if root is None:
            return None
        it = root.val
        if it.key() > key:
            return self.search_node(root.left, key)
        elif it.key() < key:
            return self.search_node(root.right, key)
        return root.val  # 返回节点对象

    def update(self, key, value):
        node = self.search_node(self.root, key)
        if node is not None:
            node.set_value(value)
            return True
        else:
            return False

    def insert(self,elem):
        self.root=self._insert(self.root,elem)
    # _代表私有函数 辅助insert函数实现插入操作
    def _insert(self,root,elem):
        if root is None:
            return BinNode(elem)
        it=root.val#rooot.val是一个Elem()对象
        if it.key()>elem.key():
            root.left=self._insert(root.left,elem)
        elif it.key()<elem.key():
            root.right=self._insert(root.right,elem)
        if it.key()==elem.key():#如果key值相同就替换
            self.update(elem.key(),elem.value())
            # root.val=elem
        return root#返回当前结点,在递归的时候只改变最后的结点

    def getmin(self,root):
        if root.left is None:
            return root.val
        else:
            return self.getmin(root.left)
    def del_min(self,root):
        if root.left is None:
            root=root.right
        else:
            root.left=self.del_min(root.left)
        return root
    def remove(self,key):
        self.remove_help(self.root,key)
    def remove_help(self,root,key):
        if root is None:
            return None
        it=root.val
        #先找到要删除的元素,思想类似于del_min(),路径中结点不会改变子结点指针值
        if it.key()>key:
            root.left=self.remove_help(root.left,key)
        elif it.key()<key:#要规范代码写法
            root.right=self.remove_help(root.right,key)
        #找到该元素,判断该结点类型(叶子、一分支、(叶子的判断可以包含在一分支判断中)二分支)
        else:
            if root.left is None:
                root=root.right
            elif root.right is None:
                root=root.left
            else:#两个分支
                temp=self.getmin(root)#获取最小元素
                root.val=temp#替换
                self.del_min(root.right)#删除最小元素(del_min返回root)
        return root

    def clear(self):
        self.root=None

    def is_Empty(self):
        return self.root is None

    def size(self, root):#递归得出二叉树大小
        if root is None:
            return 0
        else:
            return 1 + self.size(root.left) + self.size(root.right)#根结点+左子树+右子树
    def height(self, root):#递归得出二叉树高度
        if root is None:
            return 0
        else:
            return 1 + max(self.height(root.left), self.height(root.right))
    def showStructure(self, outputFile):
        with open(outputFile, 'a+',encoding='utf-8') as f:
            f.write('---------------------------\n')
            f.write(f'There are {self.size(self.root)} nodes in this BST.\n')
            f.write(f'The height of this BST is {self.height(self.root)}\n')
            f.write('---------------------------\n')
    def printInorder(self, outputFile):
        with open(outputFile, 'w',encoding='utf-8') as f:
            self._printInorder(self.root, f)
    def _printInorder(self, root, outputFile):
        if root is not None:
            self._printInorder(root.left, outputFile)
            outputFile.write(f'[{root.val.key()} - < {root.val.value()} >]\n')
            self._printInorder(root.right, outputFile)


bst=BST()
def readInputFile(bst,inputFile):#把命令文件读进来并将相应命令结果输出到文件中
    with open(inputFile, 'r',encoding='utf-8') as f:
        for line in f:
            if line.startswith('+( ') or line.startswith('=( ') or line.startswith('-( ') or line.startswith('?( ')  :
                handleOperation(bst,line.strip())
            if  line.startswith('#'):
                bst.showStructure('r.txt')
def handleOperation(bst,operation):#处理命令,将命令符号,key,value分离出来
    operation_type = operation[0]
    key_value = operation[3:-2].split(' , ')#包含3 不包含-2
    if len(key_value)>1:#命令中既有key 也有value——增改命令
        key = key_value[0]
        value = key_value[1][1:-1]#去掉引号[1:-1]
        if operation_type == '+':#判断命令类型
            bst.insert(Elem(f'({key}, "{value}")'))
        elif operation_type == '=':
            if bst.update(key, value) == True:
                with open('r.txt','a+',encoding='utf-8')as f:
                    f.write(f'update success ---{key} {value}\n')
            else:
                with open('r.txt', 'a+',encoding='utf-8') as f:
                    f.write(f'update unsuccessful ---{key}\n')
    else:#如果仅有Key 没有value——删查命令
        key=key_value[0]
        if operation_type == '-':
            root=bst.remove(key)
            if root is not None:
                with open('r.txt','a+',encoding='utf-8')as f:
                    f.write(f"remove success ---{root.val.value()}\n")
            else:
                with open('r.txt','a+',encoding='utf-8')as f:
                    f.write(f"remove unsuccessful ---{key}\n")
        elif operation_type == '?':
            result = bst.search(key)
            if result is not None:
                with open('r.txt','a+',encoding='utf-8')as f:
                    f.write(f"search success ---{key} {result}\n")
            else:
                with open('r.txt','a+',encoding='utf-8')as f:
                    f.write(f"search unsuccessful ---{key}\n")

readInputFile(bst,'testcases.txt')
bst.printInorder('bstInorder.txt')


  • 25
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值