3、二叉查找树操作(C语言和Java实现)

 看到上篇留言,要C语言实现,本篇是二叉查找树操作,上两篇也会更新C语言实现;

【问题描述】
编写一个操纵二叉查找树的程序。它将从标准输入接收命令,并将这些命令的响应
打印到标准输出。
二叉查找树是一棵二叉树,它在内部节点存储整数值。特定节点的值大于存储在其
左侧子树中的每个值,小于存储在其右侧子树中的每个值。该树不包含重复值。
请注意,在创建新节点时,需要使用malloc为它们分配空间;一旦不再需要任何已
分配的空间,就应该使用free将其释放。
【基本要求】
操纵二叉查找树的命令有4个:
插入n: 向树中添加一个值,如果还没有的话,新节点将始终作为现有节点的子节
点或根节点添加,现有节点不会因为插入数据而改变或移动。如果n不存在,因此将被
插入,程序打印插入;否则,它将打印不插入。 指令格式是一个i后跟一个十进制整数n
搜索n: 在树中搜索值n。如果n存在,程序将打印存在;否则会打印缺席。 指令格
式是一个s后跟一个空格和一个整数n
打印: 空树(即空)被打印为空字符串。节点被打印为一个(,后跟左边的子树、该
节点的项、右边的子树和),没有空格。 指令格式是一个p。 例如,对应于图3-1的输出
是((1)2((3(4))5(6)))
删除n: 从树中删除一个值。删除二叉树排序中的节点有几种策略。如果一个节点
没有子节点,可以简单地删除它;也就是说,指向它的指针可以更改为空指针。如果一
个节点有一个子节点,它可以被那个子节点替换。如果一个节点有两个子节点,其值将
被更改为其左子树中的最大元素,之前包含该值的节点将被删除。请注意,正在删除的
值可能在根节点上。 指令格式是一个d后跟一个空格和一个整数n

//C语言实现:
#include 
#include 

typedef struct TreeNode{
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode;


//创建一个新的树节点
TreeNode* createNode(int val){
    TreeNode* newNode = (TreeNode*) malloc(sizeof(TreeNode));
    newNode->val = val;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

//将值插入二叉查找树中
void insert(TreeNode** root,int val){
    if(*root == NULL){
        *root = createNode(val);
        printf("inserted\n");
        return;
    }
    if(val == (*root)->val){
        printf("not inserted\n");
        return;
    }
    if(val < (*root)->val){
        insert(&((*root)->left),val);
    }else{
        insert(&((*root)->right),val);
    }
}


//在二叉查找树中查找值
void search(TreeNode* root,int val){
    TreeNode* curr = root;
    while(curr != NULL){
        if(val == curr->val){
            printf("present\n");
            return;
        } else if(val < curr->val){
            curr = curr->left;
        } else{
            curr = curr->right;
        }
    }
    printf("absent\n");
}


void deleted(TreeNode** root, int val){
    if(*root == NULL){
        return;
    }
    if(val == (*root)->val){
        if((*root)->left == NULL){
            *root = (*root)->right;
        } else if((*root)->right == NULL){
            *root = (*root)->left;
        }else{
            TreeNode* curr = (*root)->left;
            while (curr->right != NULL){
                curr = curr->right;
            }
            (*root)->val = curr->val;
            deleted(&((*root)->left),curr->val);
        }
        printf("deleted\n");
        return;
    }
    if(val < (*root)->val){
        deleted(&((*root)->left),val);
    } else{
        deleted(&((*root)->right),val);
    }
}


//打印二叉查找树
void print(TreeNode* root){
//    if(root == NULL){
//        printf("none");
//        return;
//    }
    if(root->left != NULL){
        print(root->left);
    }
    printf("(%d",root->val);
    if (root->right != NULL) {
        print(root->right);
    }
    printf(")");
}


//释放树节点动态分配的内存
void freeTree(TreeNode* root){
    if(root == NULL){
        return;
    }
    freeTree(root->left);
    freeTree(root->right);
    free(root);
}


int main(){
    TreeNode* root = NULL;
    char command;
    int val;
    while(1){
        scanf("%c %d",&command,&val);
        switch (command) {
            case 'i':
                insert(&root,val);
                break;
            case 's':
                search(root,val);
                break;
            case 'd':
                deleted(&root,val);
            case 'p':
                print(root);
                break;
            default:
                printf("illegal\n");
        }
        //清空缓存区
        while(getchar() != '\n');
    }
    freeTree(root);
    return 0;
}

在这个代码中该程序通过标准输入接收四种命令:
- i 插入n:调用insert函数向二叉查找树中添加值n;
- s 搜索n:调用search函数在二叉查找树中查找值n的存在;
- d 删除n:调用delete函数从二叉查找树中删除值n;
- p 打印:调用print函数打印整个二叉查找树。

每次读入命令后,用switch语句根据不同的命令调用相应的函数。该程序在操作二叉查找树时,使用了动态内存分配机制,需要在不需要时及时释放相应的内存。

需要注意的是,我在这个代码中并未进行输入区分,所以打印时格式也得是`p+空格+数字`,有需要的可以自己编写此部分代码进行区分,用以优化代码。

//Java实现:

import java.util.Scanner;

@SuppressWarnings("all")
class TreeNode {
    public int val;     //节点值
    public TreeNode left;       //左子节点
    public TreeNode right;      //右子节点

    public TreeNode(int val){
        this.val = val;
        this.left = null;
        this.right = null;
    }

    public TreeNode(TreeNode left,int val,TreeNode right){
        this.left = left;
        this.val = val;
        this.right = right;
    }
}


public class demo3 {
    public static void main(String[] args) {
        SearchTree st = new SearchTree();       //创建二叉搜索树
        Scanner sc = new Scanner(System.in);

        //分别拿到指令和数据
        while (true) {          // 当仍有输入数据时继续循环
            //分别拿到指令和数据
            String s = sc.nextLine();
            if (s.length() <= 1) {
                st.print(SearchTree.root);
            }else {
                String[] s1 = s.split(" ");
                char c = s1[0].charAt(0);
                int x = Integer.parseInt(s1[1]);
                //通过指令进行对应操作
                switch (c) {
                    case 'I':
                    case 'i': {
                        st.insert(x);       //执行插入操作
                        break;
                    }
                    case 'S':
                    case 's': {
                        st.search(x);
                        break;
                    }
                    case 'D':
                    case 'd': {
                        st.delete(x);
                        break;
                    }
                    default:
                        System.out.println("您输入的格式有误,请重新输入!");
                }
            }
        }
    }
}


class SearchTree{
    public static TreeNode root = null;      //二叉树的根节点

    //插入二叉树
    public void insert(int val){
        root = insertNode(root,val);
    }

    private TreeNode insertNode(TreeNode root,int val){
        if (root == null){
            System.out.println("inserted");
            return new TreeNode(val);
        }

        if (val < root.val){
            root.left = insertNode(root.left,val);
        }else if(val > root.val){
            root.right = insertNode(root.right,val);
        }else {
            System.out.println("not inserted");
        }
        return root;
    }


    //查找二叉树
    public void search(int val){
        if (searchNode(root,val)){
            System.out.println("present");
        }else {
            System.out.println("absent");
        }
    }

    private boolean searchNode(TreeNode root,int val){
        if (root == null){
            return false;
        }
        if (val == root.val) {
            return true;
        } else if (val < root.val) {
            return searchNode(root.left,val);
        }else{
            return searchNode(root.right,val);
        }
    }

    //删除某一元素
    public void delete(int val){
        root = deleteNode(root,val);
    }

    private TreeNode deleteNode(TreeNode root,int val){
        if (root == null){
            return null;
        }
        if (val < root.val){
            root.left = deleteNode(root.left,val);
        }else if (val > root.val){
            root.right = deleteNode(root.right,val);
        }else {
            if (root.left == null && root.right == null){
                //没有子节点
                System.out.println("deleted");
                root = null;
            } else if (root.left == null) {
                //有一个右节点
                System.out.println("deleted");
                root = root.right;
            } else if (root.right == null) {
                //有一个左节点
                System.out.println("deleted");
                root = root.left;
            }else {
                //有两个子节点
                TreeNode maxNode = findMax(root.left);
                root.val = maxNode.val;
                root.left = deleteNode(root.left, maxNode.val);
                System.out.println("deleted");
            }
        }
        return root;
    }
    private TreeNode findMax(TreeNode node){
        while(node.right != null){
            node = node.right;
        }
        return node;
    }


    //打印二叉树
    public void print(TreeNode root) {
//        System.out.print("print: ");
        printNode(root);
//        System.out.print();
    }

    void printNode(TreeNode root){
        if (root != null) {
            System.out.print("(");
            printNode(root.left);
            System.out.print(root.val);
            printNode(root.right);
            System.out.print(")");
        }
    }
}


每次读入指令后,用switch语句根据不同的指令调用相应的方法。搜索树的操作中,通过向左或者向右查找叶子节点,该代码的封装操作较多,root实体搜索树一直在searchTree中,直至生命周期结束。

需要注意的是,由于输入指令时i、d和s需要读入空格,而打印操作只需要输入一个p字母,为了加以区分,我使用了一个if结构在读取完后先进行一次判断。

你可能感兴趣的:(c语言,开发语言,数据结构,java)