首頁 > 軟體

C語言範例實現二元搜尋樹詳解

2022-05-24 14:02:06

有些演演算法題裡有了這個概念,因為不知道這是什麼蒙圈了很久。

先序遍歷: 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("%dn",p->data);
   		preorder(p->left);
		preorder(p->right);
	}
}
void inorder(Node *p){//中序遍歷
	if(p!=NULL){
		inorder(p->left);
		printf("%dn",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("%dn",node->data);
		preorder(node->left);
		preorder(node->right);
	}
}
void inorder(Node*node){
	if(node!=NULL){
		inorder(node->left);
		printf("%dn",node->data);
		inorder(node->right);
	}
}
void postorder(Node*node){
	if(node!=NULL){
		postorder(node->left);
		postorder(node->right);
		printf("%dn",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==%dn",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("%dn",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語言二元搜尋樹內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com