C语言实现二叉树--->二叉查找树

2023-11-06

声明

代码实现都是自己写的,而且没有借鉴别人的代码,也没有看任何教程,只看了下二叉树的具体定义,知道大概是个什么东西
说这些只是为了说明下列代码实现肯定不是最优的,甚至在你们看来都是很垃圾的代码,不过没关系,因为这是我自己动脑筋写出来的,记录一下
ps: 我C语言功底不好,才学几天

定义

二叉查找树是二叉树中最简单的了

  1. 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

  2. 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

  3. 任意节点的左、右子树也分别为二叉查找树。

  4. 没有键值相等的节点(no duplicate nodes)。

在这里插入图片描述

假设有一个节点,这个节点的左右节点都有值,那么它左边的节点一定小于它本身,它右边的节点一定大于它本身,就和上面的图一样 (我这里实现了可以有相同元素,相同的元素会放到右子树)

C语言实现

分别创建三个文件

  1. bin_tree.h
  2. bin_tree.c
  3. bin_tree_main.c

bin_tree.h


#pragma once

#ifndef __BIN_TREE_HEAD_FILE__

#define __BIN_TREE_HEAD_FILE__

#include <stdio.h>
#include <stdlib.h>



typedef struct _node Node;


typedef struct _tree Tree;

typedef int BOOL;

#define TRUE 1

#define FALSE 0

Tree* Tree_create();

void add(Tree *self, int data);

BOOL remove_data(Tree *self, int data);

void foreach(Tree *self, void (*callback)(int data));

Node* find_node(Node *root, int data);

static void add_node(Node *root, Node *node);

static void foreach_node(Node *root, void (*callback)(int data));

static BOOL remove_node(Node *node, Node *del_node);

static Node* get_node();

Node *find_max_node(Node *root);

void delete_node(Node **node);

int if_left_or_right(Node *node);

#endif


bin_tree.c

注意下,删除节点的方法的返回值不可用,就是没有赋值正确的值,读者拿到代码后可以自己实现下


#include "bin_tree.h"

typedef struct _node
{
    struct _node *right; // 左子树
    struct _node *left; // 右子树
    struct _node *parent; // 父节点
    int data; //保存的数据
}Node;


typedef struct _tree
{
    Node *root;
}Tree;


Tree* Tree_create()
{
    Tree *tree = (Tree*) malloc(sizeof(Tree));
    tree->root = NULL; // 初始化内存
    return tree;

}

Node *find_max_node(Node *root)
{
    Node *result = root;
    if( root && root->right )
    {
        result = find_max_node(root->right);
    }

    return result;
}

void delete_node(Node **node)
{
    free(*node);
    *node = NULL;

}

// 判断当前节点是处于左子树还是右子树
// 位于左子树返回 1
// 位于右子树返回 2
// 返回 0 没有根节点
int if_left_or_right(Node *node)
{
    int result = 0;
    if( !node->parent )
    {
        result = 0;
    } else if( node == node->parent->left )
    {
        result = 1;
    } else if( node == node->parent->right )
    {
        result = 2;
    }
    
    return result;
}

void add(Tree* self, int data)
{
    Node *c = get_node();
    c->data = data;
    if( self->root )
    {
        add_node(self->root, c);
    } else 
    {
        self->root = c;
    }

}

BOOL remove_data(Tree* self, int data)
{   BOOL result = FALSE;
    Node *root = self->root;
    if( !root )
    {
        return result;
    }

    // 找到要删除的节点
    Node *del_node = find_node(root, data);
    if( !del_node )
    {
        return result;
    }
 

    if( root == del_node && !del_node->left && !del_node->right ) // 只有根节点
    {
        self->root = NULL;
        delete_node(&root);
    } else if( root == del_node && root->left )
    {
        Node *max_node = find_max_node(root->left);
        self->root = max_node;
        if( max_node != root->left ) 
        {
            max_node->parent->right = max_node->left;
            max_node->left = root->left;
            //root->left->parent = max_node;
        }  
        max_node->right = root->right;
        max_node->parent = NULL;
        root->left->parent = max_node;
        if( root->right )
        {
            root->right->parent = max_node;    
        }
        delete_node(&root);
    } else if( root == del_node && root->right )
    {
        self->root = root->right;
        root->right->parent = NULL;
        delete_node(&root);
    } else
    {
        result = remove_node(self->root, del_node);
    }

    return result;
}

void foreach(Tree* self, void (*callback)(int data))
{

    if( self->root )
    {
        foreach_node(self->root, callback);
    }

}

static void add_node(Node* root, Node* node)
{
    if( node->data >= root->data && !root->right )
    {
        root->right = node;
        node->parent = root;
    } else if( node->data < root->data && !root->left )
    {
        root->left = node;
        node->parent = root;
    } else if( node->data >= root->data )
    {
        add_node(root->right, node);
    } else if( node->data < root->data )
    {
        add_node(root->left, node);
    }
}

Node* find_node(Node* root, int data)
{
    Node *result = NULL;
    if( !root )
    {
        return result;
    }
    if( data == root->data )
    {
        result = root;
    } else if( data > root->data && root->right )
    {
        result = find_node(root->right, data);
    } else if( root->left )
    {
        result = find_node(root->left, data);
    }

    return result;

}

static void foreach_node(Node* root, void (*callback)(int data))
{
    if( root->left )
    {
        foreach_node(root->left, callback);
    }
    callback(root->data);
    if( root->right )
    {
        foreach_node(root->right, callback);
    }
}

static BOOL remove_node(Node *node, Node *del_node)
{

   // 如果当前节点没有任何子节点则直接删除
    if( !del_node->left && !del_node->right )
    {
        if( if_left_or_right(del_node) == 1 )
        {
            del_node->parent->left = NULL;
            delete_node(&del_node);
            
        } else if ( if_left_or_right(del_node) == 2 )
        {
            del_node->parent->right = NULL;
            delete_node(&del_node);
        }
    }
    // 如果当前节点有右节点或者左节点则让他的父节点指向它的孩子节点
    else if( del_node->left && !del_node->right )  // 有左子树但没有右子树
    {  

        if( if_left_or_right(del_node) == 1 )
        {
            del_node->parent->left = del_node->left;
        } else if( if_left_or_right(del_node) == 2 )
        {
            del_node->parent->right = del_node->left;
        }
        del_node->left->parent = del_node->parent;
        delete_node(&del_node);
    }
    else if( del_node->right && !del_node->left )  // 有右子树但没有左子树
    {
        if( if_left_or_right(del_node) == 1 )
        {
            del_node->parent->left = del_node->right;
        } else if( if_left_or_right(del_node) == 2 )
        {
            del_node->parent->right = del_node->right; 
        }
        del_node->right->parent = del_node->parent;
        delete_node(&del_node);
    }
    // 如果当前节点又有左节点又有右节点则需要找到要删除节点左子树中最大的节点
    // 然后再删除当前节点
    else if( del_node->left && del_node->right )
    {
        // 找到要删除的左子树的最大节点
        Node *max_node = find_max_node(del_node->left);
        if( if_left_or_right(del_node) == 1 )
        {
            del_node->parent->left = max_node;
            if( del_node->left != max_node )
            {
                max_node->parent->right = max_node->left; // 最大节点肯定是在它父节点的右边,且最大节点没有右子树
                max_node->left = del_node->left;
                del_node->left->parent = max_node;
            }
            max_node->right = del_node->right;
            del_node->right->parent = max_node;

            delete_node(&del_node);
        } else if( if_left_or_right(del_node) == 2 )
        {
            del_node->parent->right = max_node;
            if( del_node->left != max_node )
            {
                max_node->parent->right = max_node->left; // 最大节点肯定是在它父节点的右边,且最大节点没有右子树
                max_node->left = del_node->left;
                del_node->left->parent = max_node;
            }
            max_node->right = del_node->right;
            del_node->right->parent = max_node;
            delete_node(&del_node);
 
        }
    }

    return TRUE;
}

static Node* get_node()
{
    Node *node = (Node*) malloc(sizeof(Node));
    node->right = NULL;
    node->left = NULL;
    node->parent = NULL;
    return node;

}


bin_tree_main.c

#include "bin_tree.h"

void print(int data);


int main()
{
    Tree* tree = Tree_create();
    add(tree, 11);
    add(tree, 1);
    add(tree, 12);
    add(tree, 15);
    add(tree, 14);
    add(tree, 9);
    foreach(tree, print);
    printf("删除节点之后再遍历\n");
    remove_data(tree, 15);
    remove_data(tree, 9);
    remove_data(tree, 11);
    remove_data(tree, 1);
    remove_data(tree, 12);
    foreach(tree, print);
    return 0;
}

void print(int data)
{
    printf("%d\n", data);
}


在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言实现二叉树--->二叉查找树 的相关文章

  • 【javascript】导航栏

    要实现这样的效果主要有两点 第一 当鼠标经过主导航栏里面的内容就会被放大 鼠标离开后就会恢复原来的样子 第二 当鼠标经过主导航时对应的副导航的内容就会呈现
  • 一个完美的自动化测试框架应该怎么写?

    一 什么是自动化测试框架 自动化测试框架是为自动化测试用例或者脚本提供执行环境而搭建的基础设施 自动化测试框架有助于有效地开发 执行和报告自动化测试用例 优点 代码复用 提高测试效率 更高的测试覆盖率 维护成本低 更早发现和记录bug 二
  • Oracle RAC 更改网卡名称

    如 原网卡eth1 为增加网卡可靠性 把eth1和eth3绑定为bond0 主备模式提供服务 更改名称后RAC会无法启动网络服务 还需要更改的操作如下 u01 app 11 2 0 grid bin oifcfg getif u01 app
  • C#中的this

    一 C 中的this C 中的保留字this仅限于在构造函数 类的方法和类的实例中使用 在类的构造函数中出现的this作为一个值类型 它表示对正在构造的对象本身的引用 在类的方法中出现的this作为一个值类型 表示对调用该方法的对象的引用
  • WSDL(Web服务描述语言)详细解析

    WSDL Web Services Description Language Web服务描述语言 是一种XML Application 他将Web服务描述定义为一组服务访问点 客户端可以通过这些服务访问点对包含面向文档信息或面向过程调用的服

随机推荐

  • Java:珠穆朗玛峰

    需求 世界最高山峰是珠穆朗玛峰 8844 43米 8844430毫米 假如我有一张足够大的纸 它的厚度是0 1毫米 请问 我折叠多少次 可以折成珠穆朗玛峰的高度 分析 1 因为要反复折叠 所以要使用循环 但是不知道要折叠多少次 这种情况更适
  • 记一次spring循环依赖

    问题 spring循环依赖 场景 A注入B B注入A 按理来说spring是支持的处理 不会出现循环依赖的问题 但是 除了相互注入外 项目还是使用的AOP切面打印日志 使用了代理 问题就是出现在这里 源码 Whether to resort
  • 简单的整理一下Vue3的组合API

    1 Vue3的生态和优势 社区生态 逐步完善 整体优化 性能优化 TS支持优化 组合式API加持 市场使用 部分技术选型激进的公司已经在生产环境使用了vue3 社区生态 组件 插件 名称 官方地址 简介 ant design vue Ant
  • Eclipse远程调式

    JVM调式选项 Xdebug Xrunjdwp transport dt socket address 8000 server y suspend y 请务必写在一行
  • matplotlib画图

    画出第一个基本图像 import matplotlib pyplot as plt import numpy as np x np linspace 1 1 50 y x 2 1 plt plot x y plt show 用两个窗口画出两
  • java 算法结构----单链表

    相关基础知识补充 指针 表示一个数据元素逻辑意义上的存储位置 Java语言用通过对象的引用来表示指针 通过把新创建对象赋值给一个对象引用 即是让该对象引用表示 或指向 了所创建的对象 链式存储结构是基于指针实现的 我们把一个数据元素和一个指
  • 3分钟教你子网划分--(内含习题讲解)

    文章目录 一 IPV4 1 IP地址 2 IPV4地址组成 3 IP地址分类 二 子网掩码 1 网络地址与广播地址 2 子网划分 一 IPV4 1 IP地址 IP地址分为IPV4和IPV6 但现在目前大家所常用的为IPV4 IPV4是由32
  • GPU基数排序(CUDA radix sort)

    GPU基数排序 CUDA radix sort 引言 基数排序是具有固定迭代次数的排序算法 其通过对最低位到最高位的一一比较 对数值排序 本文将介绍基数排序的并行实现方法 主要包括并行基数排序 并行合并 并行归约这三种算法 本文全部代码连接
  • CentOS7.x 安装 openssh8.4、openssl1.1.1

    1 升级准备工作 1 1 查看系统版本和ssh版本 cat etc redhat release ssh V 1 2 需要将openssh升级到最新版本 直接yum安装即可 yum install openssh y 可以看已经升级到7 4
  • GCC+makefile+GDB工具

    GCC编译器 以c文件main c sub c和add c和头文件my fun h为例 代码为 1 main c include
  • 西门子200系列PLC学习课程大纲(课程筹备中)

    西门子200系列PLC学习课程大纲如下表所示 共106课 关注我 让你从菜鸟变大神 第1课 西门子200PLC概述 S7 200 PLC新特性是什么 第2课 S7 200 PLC的CPU模块介绍 第3课 S7 200 PLC编程软件介绍 第
  • jquery 访问手机摄像头_jQuery webcam plugin调用摄像头

    简介 原来做项目遇到了调用摄像头功能 php小白遇到这情况立刻就去网上搜索 最后用的 https www helloweba com vie 太烂了 作者也没说如何去使用 如果用的是框架开发更是很麻烦 今天再次发现一款比较灵活的插件jQue
  • qt帮助文档的查看(入门)

    qt帮助文档介绍
  • 语音编码之压缩

    我的书 购买链接 京东购买链接 淘宝购买链接 当当购买链接 这本书里叙述了SILK和Opus语音编解码器 这里简单的串接编解码的核心知识点 LPC LPC Linear predictive coding 在音频和语音处理领域常用于表示压缩
  • Python使用open读取文件时,如何不带换行符(\n)

    在读入一些用文本文档存储的数据时 一般都会在每一行存储一个数据 当我们用python自带的open和readlines读取每行的数据时 是会将每一行结尾的换行符 n 读入的 如下 test text txt内容 dataA dataB da
  • R语言 决策树--预测模型

    决策树 算法的目标是建立分类预测模型或回归预测模型 是一种预测模型 按目标不同可以细分为分类树和回归树 因为在展示的时候 类似于一棵倒置的树而得名 如下图 基本概念 根节点 如上图中最上方 一棵决策树只有一个根节点 中间节点 位于中间的节点
  • 找不到msvcp140.dll无法继续执行代码是什么原因?如何修复呢?

    想和大家分享一个常见的问题 找不到msvcp140 dll无法继续执行代码是什么原因 这个问题可能会让你感到困惑和烦恼 但是请放心 我会提供5个修复方法 并在最后告诉你修复完成以后需要注意的事项 找不到 msvcp140 dll 无法继续执
  • SylixOS系统如何永久修改IP地址

    1 进入 etc目录 找到startup sh文件 通过FTP下载该文件 2 用vs打开startup sh文件 将IP配置信息写入文件 保存 退出 我修改的是en2网口的IP地址 3 将修改后的startup sh文件通过FTP重新传输到
  • scrapy框架讲解

    简介 Scrapy是一个基于Python的开源异步爬虫框架 它被广泛用于从网页或App中 提取数据并将其保存到本地或数据库 由2 8版本以后提供了 http2 0协议的爬虫支持 扩展 scrapy是基于twisted框架开发而来 twist
  • C语言实现二叉树--->二叉查找树

    声明 代码实现都是自己写的 而且没有借鉴别人的代码 也没有看任何教程 只看了下二叉树的具体定义 知道大概是个什么东西 说这些只是为了说明下列代码实现肯定不是最优的 甚至在你们看来都是很垃圾的代码 不过没关系 因为这是我自己动脑筋写出来的 记