码迷,mamicode.com
首页 > 编程语言 > 详细

搜索树【链式+数组】

时间:2020-03-15 11:45:50      阅读:62      评论:0      收藏:0      [点我收藏+]

标签:不为   clu   有序   c指针   中序遍历   github   删除节点   --   测试   

数组

数组表示二叉树:

  • 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;
} 

搜索树【链式+数组】

标签:不为   clu   有序   c指针   中序遍历   github   删除节点   --   测试   

原文地址:https://www.cnblogs.com/biningooginind/p/12496351.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!