C语言实例实现二叉搜索树详解

目录

有些算法题里有了这个概念,因为不知道这是什么蒙圈了很久。

先序遍历: root——>left——>right

中序遍历: left—— root ——>right

后序遍历 :left ——right——>root

先弄一个只有四个节点的小型二叉树,实际上这种小型二叉树应用不大。

二叉树的真正应用是二叉搜索树,处理海量的数据。

代码很简单,两种遍历的代码也差不多

#include<stdio.h>
#include<stdlib.h>
typedef struct node{
	int data;
	struct node *left;
	struct node *right;
}Node;
void preorder(Node *p){//前序遍历
	if(p!=NULL){
        printf("%d\n",p->data);
   		preorder(p->left);
		preorder(p->right);
	}
}
void inorder(Node *p){//中序遍历
	if(p!=NULL){
		inorder(p->left);
		printf("%d\n",p->data);
		inorder(p->right);
	}
}
int main(){
	Node n1;
	Node n2;
	Node n3;
	Node n4;
	n1.data=15;
	n2.data=32;
	n3.data=44;
	n4.data=17;
	n1.left=&n2;
	n1.right=&n3;
	n2.left=&n4;
	n2.right=NULL;
	n3.left=NULL;
	n3.right=NULL;
	n4.left=NULL;
	n4.right=NULL;
	preorder(&n1);
	puts(" ");
	inorder(&n1);
	//     15
	//    /   \
	//  32     44
	// /  \   /  \
   //     17
	return 0;
}

二叉树代码实现

讲的非常清楚。

为了构建一颗便于查找数据的树形结构,我们规定 树的节点的数据 value leftnode<value root <value rightnode

这样的一棵树叫做二叉搜索树

为了简单记忆我们就按函数中的根被访问的顺序分为前序(pre),中序(in),后序(post)

代码主要涉及前中后序遍历和求二叉搜索树的高度,和二叉搜索树的最大值的一共5中基本操作

#include<stdio.h>
#include<stdlib.h>
#define max(a,b) a>b?a:b
typedef struct node{
	int data;
	struct node *left;
	struct node *right;
}Node;
typedef struct {
	Node *root;
}Tree;
void insert(Tree*tree,int x){
	Node *node;
	node=(Node*)malloc(sizeof (Node));
	node->data=x,node->left=NULL,node->right=NULL;
	if(tree->root==NULL){
		tree->root=node;
	}else {
			Node *temp=tree->root;
		while(temp!=NULL){

				if(x<temp->data){//如果左儿子的data<x ,考虑左边
				  if(temp->left==NULL){
				  	temp->left=node;
				  	return ;
				  }	else temp=temp->left;
				}else { //如果右儿子的data>x ,考虑右边
					if(temp->right==NULL){
						temp->right=node;
						return ;
					}else temp=temp->right;
				}
		}
	}
}
void preorder(Node*node){//二叉树的前序遍历
	if(node!=NULL){
		printf("%d\n",node->data);
		preorder(node->left);
		preorder(node->right);
	}
}
void inorder(Node*node){
	if(node!=NULL){
		inorder(node->left);
		printf("%d\n",node->data);
		inorder(node->right);
	}
}
void postorder(Node*node){
	if(node!=NULL){
		postorder(node->left);
		postorder(node->right);
		printf("%d\n",node->data);
	}
}
int get_height(Node *node){//递归求高度h=max(Heightleftsob,Heightrightson);
	if(node==NULL){
		return 0;
	}else {
		 int m1=get_height(node->left);
		 int m2=get_height(node->right);
		 int m=max(m1,m2);
		 return m+1;
	}
}
int max_e(Node*node){//递归求解最大值,max_e=max{root->data,max_leftson_e,max_rightson_e};
	if(node==NULL){
		return -0x3f3f3f3f;
	}else {
		int m1=max_e(node->left);
		int m2=max_e(node->right);
		int m=node->data;
		return max(max(m1,m2),m);
	}
}
int main(){
    Tree tree;
    tree.root=NULL;
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
	  int t;
	  scanf("%d",&t);
	  insert(&tree,t);
	}
	preorder(tree.root);
	inorder(tree.root);
	postorder(tree.root);
	int h=get_height(tree.root);
	printf("h==%d\n",h);
	int max_ele=max_e(tree.root);
	printf("max_element==%d",max_ele);
	return 0;
}

看起来很长但是实际上原理很简单,这是工程代码的特点,用数组模拟虽然会简单很多,但是无奈,两种都要会呀……

数组模拟版本:

const  int N=2e5+10;
int cnt[N];// 结点x的值val出现的次数;
int  lc[N],rc[N],sz[N];//结点x的左子结点和右子结点以及以x为节点的子树大小
int val[N];//结点x存储的数值
int n;
void print(int o){
    if(!o) return ;
    print(lc[o]);
    for(int i=1;i<=cnt[o];i++) printf("%d\n",val[o]);
    print(rc[o]);
}
int findmin(int o){
    if(!lc[o]) return o;
    return findmin(lc[o]);
}
int findmax(int o){
    if(!rc[o]) return o;
    return findmax(rc[o]);
}
void insert(int &o,int v){
   if(!o) {
       val[o=++n]=v;
       cnt[o]=sz[o]=1;
       lc[o]=rc[o]=0;
       return ;
   }
   sz[o]++;
   if(val[o]==v) {//如果节点o对应的值就是v 退出循环
       cnt[o]++;
       return ;
   }
   if(val[o]>v) insert(lc[o],v);
   if(val[o]<v) insert(rc[o],v);
}
int deletemin(int &o){
  if(!lc[o]){
      int u=0;
      o=rc[o];
      return u;//递归终点
  }else {
      int u=deletemin(lc[o]);//用左子树的最大值替换他,然后将它删除
      sz[o]-=cnt[u];
      return u;
  }
}
void del(int &o,int v){
    sz[o]--;
    if(val[o]==v){
        if(cnt[o]>1) {//结点多于一个元素,--cnt
            cnt[o]--;
            return ;
        }
      if(lc[o]&&rc[o]) o=deletemin(rc[o]);
      else o=lc[o]+rc[o];
      return ;
    }
    if(val[o]>v) del(lc[o],v);
    if(val[o]<v) del(rc[o],v);
}
//时间复杂度O(h) h为树的高度
//1.查找元素的排名
// 查找一个元素的排名,首先从根节点跳到这个元素,若向右跳,答案加上
//左儿子结点的个数加上当前结点的个数,最后答案加上终点的左子树的大小加1
int query(int o,int v){
    if(val[o]==v) return sz[lc[o]]+1;
    if(val[o]>v) return query(lc[o],v);
    if(val[o]<v) return query(rc[o],v)+sz[lc[o]]+cnt[o];
}
//2.查找排名为k的元素
//根节点的排名取决于其左子树的大小
//若其左子树的大小大于等于k,则该元素在左子树,若其左子树大小在[k-cnt,k-1]则该元素为子树的根节点。
//若其左子树的大小小于k-cnt,则称该元素在右子树中
int querykth(int o,int k){
    if(sz[lc[o]>=k] ) return querykth(lc[o],k);
    if(sz[lc[o]]<k-cnt[o]) return querykth(rc[o],k-lc[o]-cnt[o]);
    return val[o];
}

到此这篇关于C语言实例实现二叉搜索树详解的文章就介绍到这了,更多相关C语言二叉搜索树内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言实现二叉搜索树的完整总结

    1. 二叉树的构建 我们都知道二叉搜索树的特点是:当前节点的值大于它的左子树的值,小于等于右子树的值.所以我们这里可以通过迭代的方式构建二叉搜索树,当然也可以通过递归的方式构建二叉树. 定义一个结构体,表示节点: typedef struct NODE{ int va; struct NODE *left,*right; }Node; ①通过迭代的方式实现二叉搜索树的构建,值得注意的是,这种方式构建二叉搜索树的时候,需要定义一个变量,表示这个节点插入的位置是父节点的左子节点还是右子节点的位置,同

  • C语言判定一棵二叉树是否为二叉搜索树的方法分析

    本文实例讲述了C语言判定一棵二叉树是否为二叉搜索树的方法.分享给大家供大家参考,具体如下: 问题 给定一棵二叉树,判定该二叉树是否是二叉搜索树(Binary Search Tree)? 解法1:暴力搜索 首先说明一下二叉树和二叉搜索树的区别.二叉树指这样的树结构,它的每个结点的孩子数目最多为2个:二叉搜索树是一种二叉树,但是它有附加的一些约束条件,这些约束条件必须对每个结点都成立: 结点node的左子树所有结点的值都小于node的值. 结点node的右子树所有结点的值都大于node的值. 结点n

  • C语言实例实现二叉搜索树详解

    目录 有些算法题里有了这个概念,因为不知道这是什么蒙圈了很久. 先序遍历: root——>left——>right 中序遍历: left—— root ——>right 后序遍历 :left ——right——>root 先弄一个只有四个节点的小型二叉树,实际上这种小型二叉树应用不大. 二叉树的真正应用是二叉搜索树,处理海量的数据. 代码很简单,两种遍历的代码也差不多 #include<stdio.h> #include<stdlib.h> typedef

  • Java数据结构之二叉搜索树详解

    目录 前言 性质 实现 节点结构 初始化 插入节点 查找节点 删除节点 最后 前言 今天leetcode的每日一题450是关于删除二叉搜索树节点的,题目要求删除指定值的节点,并且需要保证二叉搜索树性质不变,做完之后,我觉得这道题将二叉搜索树特性凸显的很好,首先需要查找指定节点,然后删除节点并且保持二叉搜索树性质不变,就想利用这个题目讲讲二叉搜索树. 二叉搜索树作为一个经典的数据结构,具有链表的快速插入与删除的特点,同时查询效率也很优秀,所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数

  • C语言 指针与二维数组详解

    二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有"缝隙".以下面的二维数组 a 为例: int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} }; 从概念上理解,a 的分布像一个矩阵: 0   1   2   3 4   5   6   7 8   9  10  11 但在内存中,a 的分布是一维线性的,整个数组占用一块连续的内存: C语言中的二维数组是按行排列的,也就是先存放 a[

  • PHP实现绘制二叉树图形显示功能详解【包括二叉搜索树、平衡树及红黑树】

    本文实例讲述了PHP实现绘制二叉树图形显示功能.分享给大家供大家参考,具体如下: 前言: 最近老师布置了一个作业:理解并实现平衡二叉树和红黑树,本来老师是说用C#写的,但是我学的C#基本都还给老师了,怎么办?那就用现在最熟悉的语言PHP来写吧! 有一个问题来了,书上在讲解树的时候基本上会给出形象的树形图.但是当我们自己试着实现某种树,在调试.输出的时候确只能以字符的形式顺序地输出.这给调试等方面带来了很大的不便.然后在各种百度之后,我发现利用PHP实现二叉树的图形显示的资源几乎是零!好吧,那我就

  • C#二叉搜索树插入算法实例分析

    本文实例讲述了C#二叉搜索树插入算法.分享给大家供大家参考.具体实现方法如下: public class BinaryTreeNode { public BinaryTreeNode Left { get; set; } public BinaryTreeNode Right { get; set; } public int Data { get; set; } public BinaryTreeNode(int data) { this.Data = data; } } public void

  • Java创建二叉搜索树,实现搜索,插入,删除的操作实例

    Java实现的二叉搜索树,并实现对该树的搜索,插入,删除操作(合并删除,复制删除) 首先我们要有一个编码的思路,大致如下: 1.查找:根据二叉搜索树的数据特点,我们可以根据节点的值得比较来实现查找,查找值大于当前节点时向右走,反之向左走! 2.插入:我们应该知道,插入的全部都是叶子节点,所以我们就需要找到要进行插入的叶子节点的位置,插入的思路与查找的思路一致. 3.删除: 1)合并删除:一般来说会遇到以下几种情况,被删节点有左子树没右子树,此时要让当前节点的父节点指向当前节点的左子树:当被删节点

  • Java二叉搜索树遍历操作详解【前序、中序、后序、层次、广度优先遍历】

    本文实例讲述了Java二叉搜索树遍历操作.分享给大家供大家参考,具体如下: 前言:在上一节Java二叉搜索树基础中,我们对树及其相关知识做了了解,对二叉搜索树做了基本的实现,下面我们继续完善我们的二叉搜索树. 对于二叉树,有深度遍历和广度遍历,深度遍历有前序.中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历,如图: 因为树的定义本身就是递归定义,所以对于前序.中序以及后序这三种遍历我们使用递归的方法实现,而对于广度优先遍历需要选择其他数据结构实现,本例中我们使用队列来实现广度优先遍历.

  • Java二叉搜索树基础原理与实现方法详解

    本文实例讲述了Java二叉搜索树基础原理与实现方法.分享给大家供大家参考,具体如下: 前言:本文通过先通过了解一些二叉树基础知识,然后在转向学习二分搜索树. 1 树 1.1 树的定义 树(Tree)是n(n>=0)个节点的有限集.n=0时称为空树.在任意一颗非空树中: (1)有且仅有一个特定的称为根(Root)的节点: (2)当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1.T2........Tn,其中每一个集合本身又是一棵树,并且称为根的子树. 此外,树的定义还需要强调以

  • Java底层基于二叉搜索树实现集合和映射/集合Set功能详解

    本文实例讲述了Java底层基于二叉搜索树实现集合和映射功能.分享给大家供大家参考,具体如下: 前言:在第5章的系列学习中,已经实现了关于二叉搜索树的相关操作,详情查看第5章即可.在本节中着重学习使用底层是我们已经封装好的二叉搜索树相关操作来实现一个基本的集合(set)这种数据结构. 集合set的特性: 集合Set存储的元素是无序的.不可重复的.为了能达到这种特性就需要寻找可以作为支撑的底层数据结构. 这里选用之前自己实现的二叉搜索树,这是由于该二叉树是不能盛放重复元素的.因此我们可以使用二叉搜索

随机推荐