C語言實(shí)例實(shí)現(xiàn)二叉搜索樹詳解
有些算法題里有了這個(gè)概念,因?yàn)椴恢肋@是什么蒙圈了很久。
先序遍歷: root——>left——>right
中序遍歷: left—— root ——>right
后序遍歷 :left ——right——>root
先弄一個(gè)只有四個(gè)節(jié)點(diǎn)的小型二叉樹,實(shí)際上這種小型二叉樹應(yīng)用不大。
二叉樹的真正應(yīng)用是二叉搜索樹,處理海量的數(shù)據(jù)。
代碼很簡單,兩種遍歷的代碼也差不多
#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;
}講的非常清楚。
為了構(gòu)建一顆便于查找數(shù)據(jù)的樹形結(jié)構(gòu),我們規(guī)定 樹的節(jié)點(diǎn)的數(shù)據(jù) value leftnode<value root <value rightnode
這樣的一棵樹叫做二叉搜索樹
為了簡單記憶我們就按函數(shù)中的根被訪問的順序分為前序(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;
}看起來很長但是實(shí)際上原理很簡單,這是工程代碼的特點(diǎn),用數(shù)組模擬雖然會(huì)簡單很多,但是無奈,兩種都要會(huì)呀……
數(shù)組模擬版本:
const int N=2e5+10;
int cnt[N];// 結(jié)點(diǎn)x的值val出現(xiàn)的次數(shù);
int lc[N],rc[N],sz[N];//結(jié)點(diǎn)x的左子結(jié)點(diǎn)和右子結(jié)點(diǎn)以及以x為節(jié)點(diǎn)的子樹大小
int val[N];//結(jié)點(diǎn)x存儲(chǔ)的數(shù)值
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) {//如果節(jié)點(diǎn)o對應(yīng)的值就是v 退出循環(huán)
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;//遞歸終點(diǎn)
}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) {//結(jié)點(diǎn)多于一個(gè)元素,--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);
}
//時(shí)間復(fù)雜度O(h) h為樹的高度
//1.查找元素的排名
// 查找一個(gè)元素的排名,首先從根節(jié)點(diǎn)跳到這個(gè)元素,若向右跳,答案加上
//左兒子結(jié)點(diǎn)的個(gè)數(shù)加上當(dāng)前結(jié)點(diǎn)的個(gè)數(shù),最后答案加上終點(diǎn)的左子樹的大小加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的元素
//根節(jié)點(diǎn)的排名取決于其左子樹的大小
//若其左子樹的大小大于等于k,則該元素在左子樹,若其左子樹大小在[k-cnt,k-1]則該元素為子樹的根節(jié)點(diǎn)。
//若其左子樹的大小小于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];
}到此這篇關(guān)于C語言實(shí)例實(shí)現(xiàn)二叉搜索樹詳解的文章就介紹到這了,更多相關(guān)C語言二叉搜索樹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)水仙花數(shù)判斷實(shí)例
大家好,本篇文章主要講的是C++實(shí)現(xiàn)水仙花數(shù)判斷實(shí)例,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01
C語言函數(shù)棧幀的創(chuàng)建與銷毀原理圖解
我們知道c語言中函數(shù)都是被調(diào)用的,main函數(shù)里面能調(diào)用其他函數(shù),其實(shí)main函數(shù)也是被別的函數(shù)調(diào)用的,下面通過本文給大家分享c語言函數(shù)棧幀的創(chuàng)建和銷毀過程,一起看看吧2022-05-05
win10系統(tǒng)下?VS2019點(diǎn)云庫PCL1.12.0的安裝與配置教程
點(diǎn)云庫全稱是Point?Cloud?Library(PCL),是一個(gè)獨(dú)立的、大規(guī)模的、開放的2D/3D圖像和點(diǎn)云處理項(xiàng)目,這篇文章主要介紹了win10系統(tǒng)下?VS2019點(diǎn)云庫PCL1.12.0的安裝與配置,需要的朋友可以參考下2022-07-07
c++ 標(biāo)準(zhǔn)庫多線程問題小結(jié)
C++11 引入了<thread>庫,使得多線程編程更加方便,以下是一些基本概念和示例,幫助你理解如何在 C++ 中進(jìn)行多線程編程,這篇文章主要介紹了c++ 標(biāo)準(zhǔn)庫多線程,需要的朋友可以參考下2025-03-03
C++中二進(jìn)制數(shù)據(jù)序列化和反序列化詳解
這篇文章主要為大家詳細(xì)介紹了C++中二進(jìn)制數(shù)據(jù)序列化和反序列化的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下2023-11-11

