zoukankan      html  css  js  c++  java
  • 搜索树【链式+数组】

    数组

    数组表示二叉树:

    • root
      • left:root*2+1
      • right:root*2+2

    比如 0号节点的左孩子是1 右孩子是2

    1号节点的左孩子是3 右孩子是4

    2号节点的左孩子是5 右孩子是6

    1、定义结构体

    int tree[1000]={0}; //存放值的数组
    const int NUL=0;//定义0为空
    

    2、找树的最小值和最大值的节点位置

    int findMin(int root) //找最小的 往左边找 
    {
    	if(tree[root*2+1]==NUL)
            return root;
        return findMin(root*2+1);
    }
    
    
    
    int findMax(int root) //找最小的 往左边找 
    {
    	if(tree[root*2+2]==NUL)
            return root;
        return findMin(root*2+2);
    }
    
    

    3、插入节点

    void Insert(int root,int v)
    {
    	if(tree[root]==NUL)
    	{
    		tree[root]=v;
    		return ;
    	}
    	else if(tree[root]>v)
    	{
    		Insert(root*2+1,v);  //插入到左树 	
    	}	
    	else
    	{
    		Insert(root*2+2,v); //插入到右树 
    	}	
    		
    }
    

    4、判断节点是否存在

    bool isExist(int root,int val) //是否存在数 二分 用循环代替递归
    {
        while(tree[root]!=NUL)
        {
            if(tree[root]==val)
                return true;
            if(tree[root]>val) //小的都在左边 大的都在右边
                root=root*2+1;
            else
                root=root*2+2;
        }
        return false;
    }
    

    5、中序遍历:中序遍历都是顺序是有序的 降序

    void PrintAll(int root)//中序遍历
    {
        if(tree[root]==NUL)
            return;
        else
        {
        	//左中右 刚好有序 
            PrintAll(root*2+1);  
            cout<<tree[root]<<endl;
            PrintAll(root*2+2);
        }
    }
    

    6、删除节点

    删除节点比较麻烦,但是主要有三种情况

    1. 待删的节点没有孩子:直接删除

    2. 待删的节点有右孩子:

      将右子树的最小的和根节点替换,这样才能保持二叉树还符合排序树的规则,再删除替换后的节点(注意这里要递归删除,因为可能右子树最小的值有左孩子)

    3. 待删除的节点没有右孩子,但是有左孩子:

      将左边子树最大值和根节点换,类似2步递归删除

    代码如下:

    void Delete(int root,int x)
    {
    	
    	if(tree[root]>x)
    	{
    		Delete(root*2+1,x);  //在左边 
    	}
    	else if(tree[root]<x)
            Delete(root*2+2,x); //在右边
    	else
    	{
    		if (tree[root*2+1]==NUL && tree[root*2+2]==NUL){ //左右孩子都为空 直接删除即可 
    				tree[root] = NUL;
    		}
    		else if(tree[root*2+2]!=NUL){  //右边孩子不为空 将右边最小的和根换 然后递归删除 因为最小的那个节点可能还有右孩子 
    			int right_small = findMin(root*2+2);
    			swap(tree[root],tree[right_small]);
    			Delete(right_small,x);
    		}
    		else{ //右边空左边不空 则将左边最大的和根节点换  然后递归删除 因为可能左边节点有左孩子 
    			int left_max = findMax(root*2+1);
    			swap(tree[root],tree[left_max]);
    			Delete(left_max,x);
    		} 
    	}	 
    	
     } 
    

    7、测试代码

    
    int main()
    {
    	int root = 0;
    	Insert(root,10);
    	Insert(root,4);
    	Insert(root,8);
    	Insert(root,20);
    	Insert(root,3);
    	Insert(root,1);
    	PrintAll(root);
    	
    	cout<<"-----------------"<<endl;
    	Delete(root,4);
    	Delete(root,10);
    	
    	
    	PrintAll(root);
    	
    	
    } 
    

    1
    3
    4
    8
    10

    20


    1
    3
    8
    20




    https://github.com/biningo/Algorithm.

    链式结构

    差不多,这里贴一下代码,由于c指针比较麻烦,所以讲删除的节点值设置为0代表删除

    #include<iostream>
    #include<cstdlib>
    using namespace std;
    #define NULL 0
    struct Node {
    	int val;
    	Node* left=NULL;
    	Node* right=NULL;
    	Node* pre=NULL;
    };
    
    
    
    Node* FindMin(Node* root) { //寻找最小的节点 也就是寻找最左边的节点
    	if (root->left==NULL)
    		return root;
    	return FindMin(root->left);
    }
    Node* FindMax(Node* root) {
    	if(root->right==NULL)
    		return root;
    	return FindMax(root->right);
    }
    
    //-------------------插入--------------------------
    void Insert(Node** root,int val) {
    	if(*root==NULL){
    		
    		*root = (Node*)malloc(sizeof(Node));
    		(*root)->left = NULL;
    		(*root)->right= NULL;
    		(*root)->val  = val;
    		return;	
    	}
    	
    	if(val>(*root)->val) //大于根 则插入到右边
    		Insert(&(*root)->right,val);
    	else if(val<(*root)->val)  //小于根则插入到左边
    		Insert(&(*root)->left,val);
    	else
    		cout<<"节点已经存在"<<endl;
    	return;
    }
    
    
    //---------------------节点是否存在 ---------------
    bool IsExist(Node* root,int val) {
    	if(root->val==val)
    		return true;
    	else if(val>root->val)
    		return IsExist(root->right,val);
    	else
    		return IsExist(root->left,val);
    }
    
    
    //---------------------中序遍历,有序打印------------
    void PrintAll(Node* root) {
    	if(root==NULL)
    		return;
    	PrintAll(root->left); //遍历左子树
    	if(root->val!=0){
    		cout<<root->val<<endl;      //左中右	
    	} 
    	PrintAll(root->right);//遍历右子树
    }
    
    
    //-------------------删除节点 递归版 删除的值为0-----------------------
    void Delete(Node*root,int val) {
    	if(val>root->val)
    		Delete(root->right,val);
    	else if(val<root->val)
    		Delete(root->left,val);
    	else { //找到节点了
    		if(root->left==NULL && root->right==NULL){ //没有孩子 直接free
    			root->val=0;
    		}
    		else if(root->right!=NULL) { //有右孩子 则找右边最小的孩子替换根节点 让树仍然保持有序
    			Node* right_min = FindMin(root->right);
    			swap(root->val,right_min->val); //交换值
    			Delete(right_min,val); //递归删除 因为可能右边最小的节点还有右孩子
    		} 
    		else { //只有左孩子 则找左边最大的和根节点互换
    			Node* left_max = FindMax(root->left);
    			swap(root->val,left_max->val);
    			Delete(left_max,val); //同理
    		}	
    	}
    }
    
    int main(){
    	
    	Node* root=NULL; 
    	
    	Insert(&root,10);
    	Insert(&root,4);
    	Insert(&root,8);
    	Insert(&root,20);
    	Insert(&root,3);
    	Insert(&root,1);
    	PrintAll(root);
    //	
    	cout<<"-----------------"<<endl;
    	Delete(root,4);
    	Delete(root,10);
    //	
    //	
    
    	PrintAll(root);
    	
    	return 0;
    } 
    
    
  • 相关阅读:
    vs2008 当前上下文不存在名称xxx 解决办法
    SQL Server 2008故障转移集群+数据库镜像配置实例之一
    通过JavaScript获取页面大小
    使用JavaScript判断浏览器类型
    sql2008安装图解sql2008安装全过程
    Sqlserver中对时间类型的字段转换
    SQL Server 2008故障转移集群+数据库镜像配置实例之三
    这年头口罩都成时尚品
    一位软件工程师的6年总结[转]
    MS SQL Server查询优化方法[转]
  • 原文地址:https://www.cnblogs.com/biningooginind/p/12496351.html
Copyright © 2011-2022 走看看