二叉排序树的应用(基于二叉排序树的个人通信录)

本文介绍了一种使用二叉排序树作为数据结构实现个人通信录的高效管理方法,尤其强调了删除操作的实现细节。通过避免频繁排序,二叉排序树能够快速查寻和删除联系人信息,提高了通信录的性能。删除操作分为叶节点、单子树节点和双子树节点三种情况处理,确保了通信录数据的准确性和系统稳定性。
摘要由CSDN通过智能技术生成

     在日常生活中,个人通信录是我们不可少的,不管是纸式的个人通信录 还是我们手机中的个人通信录,查寻是其最基本的操作,几乎所有的操作都是在查寻的基础上进行的,所以,查寻时间的快慢很大程度上决定了整个通信录的性能。所以,一个有着良好界面、查寻速快的通信录,是人们所追求的。

本设计应用折半查寻法 的技术思想进行查寻,从本思想出发,可以有两种数据组织方式:一是应用链表进行组织数据,由于折半查寻法的特殊性,所要进行查寻的数据列必须是有序的数据列,这样要求对数据列进行排序。出于系统实时查寻的考虑,每次对通信录进行改变后都得进行重新排序,这样才能保证数据列是实时有序的。这样当操作量大时,排序所消耗的时间对整个系统有很大的影响。

二是应用二叉排序树来组织数据,由于二叉排序树是应用折半查寻法思想进行对数据进行存储的,所以,其左孩子大于双亲结点、右孩子小于双亲结点(或者左孩子小于双亲结点、右孩子大于双亲结点),这样就可以应用折半查寻法的思想进行查寻,从而减少对排序时所消耗的时间。

本设计采用第二种方法,即应用二叉排序树进行组织数据,在此基础上进行对个人通信录的各种操作。由于删除操作是本设计的重点,删除操作的成功与否直接影响到整个系统的成败,所以在此进行详细分析一下删除操作的实现。

此功能函数主要应用于删除将要进行删除的记录,此操作较其它几个操作难一点,同时也是此次设计的重点,所以,本函数的成败可以直接影响到本次设计的成败,同时,在进行二叉排序树进行组织时,如果不从系统的整体进行考虑,只想到简单地实现删除功能,将会出现错误。

在设计初期,由于没有考虑所有可能的情况,所以在进行删除最后一个结点时,总会出现内存不能引用的错误。最后想到应用浪费一个结点空间的技术进行处理此问题,就是根结点用来保存二叉排序树的某些信息,而不保存记录,与我们单链表中的头结点一样,这样做解决了上面所说的问题,同时在进行查寻双亲结点时也带来了很大的方便。

有关二叉排序树的删除的有关问题,请读者参考相关的参考文献 ,在此不再进行说明,本节重点在于说明本课程设计中有关删除的问题。

在本设计中,删除的首要条件是找到将要进行删除结点的双亲结点,由于根结点不用于存储记录,所以,可以不用进行判断根结点的情况,进行查寻双亲结点时,从根结点开始,首先进行判断根结点的左右子树是否为空,如果根结点的左右子树为空,则返回 NULL ,如果根结点的左子树(右子树)不为空,则将其左子树(右子树)的记录的学号与将要进行删除的学号进行比较,如果相等,则返回根结点;否则进行比较,如果左子树(右子树)不为空,且左子树(右子树)的学号大于(小于)要进行删除的学号,则进行递归在左子树(右子树)中进行查寻,直到查寻到或者当前结点的左右子树为空时结束。如果当前结点的学号与要进行删除的学号不相等,且当前结点的左右子树为空,则返回空,结束查寻过程。

经过对双亲结点的查寻,如果没有此记录,则进行提示,否则进行删除操作 [1] [5] ,在进行删除时,有以下几种可能,以下操作中假设每次把要进行删除结点进行删除后,同时也释放了此结点所占用的内存空间,防止内存在运行过程中丢失。

第一:要进行删除的结点为叶结点,直接把其从二叉排序树中进行删除。

第二:此结点只有左子树或者右子树,这种情况下只需将只需把此结点的左子树或者右子树替换为双亲结点的左子树。

第三:此结点有左子树同时有也右子树,此种操作比较复杂,其中有两种方法进行删除,本课程设计中应用的方法是从某子树中找出一个结点(假设为 Temp ),将其值代替要进行删除结点的值,再把 Temp 结点进行删除。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉排序树是一种特殊的二叉树,它的左子树中的所有节点的值都小于根节点的值,右子树中的所有节点的值都大于根节点的值。因此,二叉排序树可以用来实现快速的查找、插入和删除操作。下面是一个基于二叉排序树个人通信录的C语言实现: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 定义二叉排序树的节点结构体 typedef struct BSTNode { char name[20]; // 姓名 char phone[12]; // 电话号码 struct BSTNode *left; // 左子树 struct BSTNode *right; // 右子树 } BSTNode; // 插入节点 BSTNode* insert(BSTNode *root, char *name, char *phone) { if (root == NULL) { // 如果根节点为空,创建新节点 root = (BSTNode*)malloc(sizeof(BSTNode)); strcpy(root->name, name); strcpy(root->phone, phone); root->left = NULL; root->right = NULL; } else if (strcmp(name, root->name) < 0) { // 如果插入的姓名小于根节点的姓名,插入到左子树 root->left = insert(root->left, name, phone); } else if (strcmp(name, root->name) > 0) { // 如果插入的姓名大于根节点的姓名,插入到右子树 root->right = insert(root->right, name, phone); } else { // 如果插入的姓名已经存在,更新电话号码 strcpy(root->phone, phone); } return root; } // 查找节点 BSTNode* search(BSTNode *root, char *name) { if (root == NULL) { // 如果根节点为空,返回NULL return NULL; } else if (strcmp(name, root->name) < 0) { // 如果查找的姓名小于根节点的姓名,递归查找左子树 return search(root->left, name); } else if (strcmp(name, root->name) > 0) { // 如果查找的姓名大于根节点的姓名,递归查找右子树 return search(root->right, name); } else { // 如果查找的姓名等于根节点的姓名,返回根节点 return root; } } // 删除节点 BSTNode* delete(BSTNode *root, char *name) { if (root == NULL) { // 如果根节点为空,返回NULL return NULL; } else if (strcmp(name, root->name) < 0) { // 如果要删除的姓名小于根节点的姓名,递归删除左子树 root->left = delete(root->left, name); } else if (strcmp(name, root->name) > 0) { // 如果要删除的姓名大于根节点的姓名,递归删除右子树 root->right = delete(root->right, name); } else { // 如果要删除的姓名等于根节点的姓名 if (root->left == NULL && root->right == NULL) { // 如果根节点没有左右子树,直接删除 free(root); root = NULL; } else if (root->left == NULL) { // 如果根节点只有右子树,用右子树替换根节点 BSTNode *temp = root; root = root->right; free(temp); } else if (root->right == NULL) { // 如果根节点只有左子树,用左子树替换根节点 BSTNode *temp = root; root = root->left; free(temp); } else { // 如果根节点既有左子树又有右子树,用右子树中最小的节点替换根节点 BSTNode *temp = root->right; while (temp->left != NULL) { temp = temp->left; } strcpy(root->name, temp->name); strcpy(root->phone, temp->phone); root->right = delete(root->right, temp->name); } } return root; } // 中序遍历 void inorder(BSTNode *root) { if (root != NULL) { inorder(root->left); printf("%s\t%s\n", root->name, root->phone); inorder(root->right); } } int main() { BSTNode *root = NULL; int choice; char name[20], phone[12]; while (1) { printf("1.插入联系人\n2.查找联系人\n3.删除联系人\n4.显示所有联系人\n5.退出\n"); printf("请输入操作编号:"); scanf("%d", &choice); switch (choice) { case 1: printf("请输入姓名和电话号码:"); scanf("%s%s", name, phone); root = insert(root, name, phone); printf("联系人已插入\n"); break; case 2: printf("请输入要查找的姓名:"); scanf("%s", name); BSTNode *node = search(root, name); if (node == NULL) { printf("联系人不存在\n"); } else { printf("%s\t%s\n", node->name, node->phone); } break; case 3: printf("请输入要删除的姓名:"); scanf("%s", name); root = delete(root, name); printf("联系人已删除\n"); break; case 4: printf("姓名\t电话号码\n"); inorder(root); break; case 5: exit(0); default: printf("无效的操作编号\n"); break; } } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值