先序序列建立一颗二叉树及哈夫曼树

目录

1.先序序列建立一颗二叉树

2.哈夫曼树的创建与打印

3.素数解决之树筛法

4.红黑树

4.1 简介

4.2 红黑树性质

4.3 为什么这样的树是平衡的

4.4 Java8中HashMap链表使用红黑树而不是AVL树

4.5 既然红黑树那么好,为啥hashmap不直接采用红黑树,而是当大于8个的时候才转换红黑树

4.6 红黑树应用实例


1.先序序列建立一颗二叉树

输入(在空子树处添加空格字符或“*”的二叉树,本例中以“*”判断空子树)先序序列(设每个元素是一个字符),按先序遍历的顺序,建立二叉链表,并将该二叉链表根结点指针赋给root 。

如果输入字符不是“*”,则建立一个新结点,然后建立其左子树和右子树;如果是空格则返回,继续进行下一次操作。

输入:一个包含空子树符号的先序序列,例如:序列ABC**DE**F**G**

输出:建立一颗二叉链表表示的二叉树T,根指针为root,结果输出先序遍历二叉树后的序列A B C D E F G

import java.util.Scanner;

public class InOrder {
    static int count = 0;

    // 创建节点
    public static class Node {
        private char data;
        private Node left = null;
        private Node right = null;

        public Node(char data) {
            this.data = data;
        }
    }

    // 先序创建二叉树
    public static Node create(String datas) {
        Node root = null;
        char c = datas.charAt(count);
        if (c != '*') {
            root = new Node(c);
            count++;
            root.left = create(datas);
            count++;
            root.right = create(datas);
        }
        return root;
    }

    // 输出二叉树
    public static void prePrint(Node root) {
        System.out.print(root.data);
        if (root.left != null) {
            prePrint(root.left);
        }
        if (root.right != null) {
            prePrint(root.right);
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入先序序列:");
        String datas = scanner.next();
        Node root = create(datas);
        prePrint(root);
    }
}

2.哈夫曼树的创建与打印

根据给定的字符及其权值建立一棵哈夫曼树,并输出已建好的哈夫曼树的各结点的编码。

public class HuffmanTree {


    /*
     * 哈夫曼树的结点
     */
    public static class Node {
        private char data;
        private int weight;
        private int parent;
        public Node left = null;
        public Node right = null;

        public Node(int data, int weight, int parent) {
            this.data = (char) (data + 'A');
            this.weight = weight;
            this.parent = parent;
        }
    }


    /*
     * 非递归创建哈夫曼树,返回权值最大的节点
     */
    public Node create(Stack<Integer> stack, int[][] a) { // 创建哈夫曼树
        Queue<Node> queue = new LinkedList<>();
        int weight, data, parent;
        Node temp = null;

        while (!stack.isEmpty()) {
            Node root = null;
            data = -1;// 设置默认符号为@
            parent = 0;
            /*
             * 创建或选择根节点
             */
            if (!queue.isEmpty()) {
                // 取队头元素为根节点
                root = queue.poll();
            } else { // 创建根节点,仅执行一次
                weight = stack.pop();
                for (int i = 0; i < a.length; i++) {
                    if (a[i][1] == weight) {
                        data = a[i][0];
                    }
                }
                root = new Node(data, weight, parent);
                temp = root;
            }

            /*
             * 创建左子树
             */
            if (!stack.isEmpty()) {
                parent = root.weight;
                weight = stack.pop();
                for (int i = 0; i < a.length; i++) {
                    if (a[i][1] == weight) {
                        data = a[i][0];
                    }
                }
                root.left = new Node(data, weight, parent);
                queue.add(root.left);
            }
            /*
             * 创建右子树
             */
            if (!stack.isEmpty()) {
                parent = root.weight;
                weight = stack.pop();
                for (int i = 0; i < a.length; i++) {
                    if (a[i][1] == weight) {
                        data = a[i][0];
                    }
                }
                root.right = new Node(data, weight, parent);
                queue.add(root.right);
            }
        }
        return temp;
    }


    /*
     * 递归打印哈夫曼树
     */
    public static void printTree(Node root) {
        if (root.left != null && root.right != null) {// 哈夫曼树没有度为1的点
            System.out.println(root.data + "\t" + root.weight + "\t"
                    + root.parent + "\t" + root.left.data + "\t"
                    + root.right.data);
        } else {
            // -1代表无子节点
            System.out.println(root.data + "\t" + root.weight + "\t"
                    + root.parent + "\t" + "-1" + "\t" + "-1");
        }
        if (root.left != null) {
            printTree(root.left);
        }

        if (root.right != null) {
            printTree(root.right);
        }
    }

    /*
     * 处理输入的数组,返回存储权值的栈
     */
    public Stack<Integer> dealArray(int[][] a) {

        Stack<Integer> stack = new Stack<>();

        List<Integer> array = new ArrayList<>();

        for (int i = 0; i < a.length; i++) {
            array.add(a[i][1]);
        }

        Collections.sort(array);// 排序
        int min1;
        for (int i = 0; i < array.size() - 1; ) {
            stack.add(array.get(i));
            stack.add(array.get(i + 1));
            int sum = array.get(i) + array.get(i + 1);
            array.add(sum);
            array.remove(array.get(i));
            array.remove(array.get(i)); // 一定要为array.get(i),不能为array.get(i+1)!
            Collections.sort(array);
            i = 0;
        }
        stack.add(array.get(0));
        return stack;
    }


    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("请输入需哈夫曼编码的字符及其权值:\n输入规则如(A1 B2 C3)");
        String s = in.nextLine();
        s = s.replace(" ", "");
        int[][] a = new int[s.length() / 2][2];
        int j = 0;
        for (int i = 0; i < s.length(); i++) {// 用二维数组存储字符与权值
            if (i % 2 == 0) {
                a[j][0] = s.charAt(i) - 'A';
            } else {
                a[j][1] = s.charAt(i) - '0';
                j++;
            }
        }
        // C3 B4 A5
        HuffmanTree tree = new HuffmanTree();
        Stack<Integer> stack = tree.dealArray(a);
        Node root = tree.create(stack, a);
        System.out.println("所带字符\t权值\t双亲节点\t左孩子\t右孩子");
        printTree(root);
        System.out.println("备注:\n字符默认为@\n0代表无双亲节点\n-1代表无孩子");
    }
}

3.素数解决之树筛法

算法训练 Torry的困惑(基本型)  

时间限制:1.0s   内存限制:512.0MB

问题描述

  Torry从小喜爱数学。一天,老师告诉他,像2、3、5、7……这样的数叫做质数。Torry突然想到一个问题,前10、100、1000、10000……个质数的乘积是多少呢?他把这个问题告诉老师。老师愣住了,一时回答不出来。于是Torry求助于会编程的你,请你算出前n个质数的乘积。不过,考虑到你才接触编程不久,Torry只要你算出这个数模上50000的值。

输入格式

  仅包含一个正整数n,其中n<=100000。

输出格式

  输出一行,即前n个质数的乘积模50000的值。

样例输入

1

样例输出

2
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		System.out.println(calPrimeNumber(n));
	}

	private static int calPrimeNumber(int n) {
		boolean[] prime=new boolean[10*n];
		for(int i=2;i<prime.length;i++){
			if(i%2==0)
				prime[i]=false;
			else
				prime[i]=true;
		}
		for(int i=3;i<=Math.sqrt(prime.length);i+=2){
			for(int j=i+i;j<prime.length;j+=i){//数筛法	
				prime[j]=false;
			}
		}
		prime[2]=true;
		int k=0,ans=1;
		for(int i=2;i<prime.length;i++){
			if(k==n)
				break;
			if(prime[i]){
				ans*=i;
				ans%=50000;
				k++;
			}
		}
		return ans;
	}
	
}

4.红黑树

4.1 简介

红黑树是一种自平衡二叉搜索树,不能保证非常严格的平衡性,但是其平衡性仍然足以确保以O(logN)的时间复杂度进行插入、删除和检索操作。
它需要更少的内存,并且可以更快的进行再平衡,所以它常在树需要被频繁修改的情况下使用。

4.2 红黑树性质

1)每个节点要么是红色节点,要么是黑色节点  
2)根节点是黑色节点  
3)叶节点是空节点,也称为黑色节点  
4)每个红色节点必须有两个黑色子节点,也就是说,一个红色节点不可能有红色子节点(虽然黑色节点可以有黑色子节点)  
5)每一条从某一节点至叶节点的路径必须包含相同数量的黑色子节点  

4.3 为什么这样的树是平衡的

根据性质5)假设从某节点(根节点)到叶节点有路径1与路径2,每条路径均有b个黑色节点,最坏情况下,  
  + 红色节点最少数量为0,则路径1共有b个节点  
  + 红色节点最大数量为b(性质4决定红色节点数不会超过一半), 路径2共有2b个节点
即使在最极端的情况下,两条路径的长度相差也不会超过一倍,这足以确保在O(logN)的时间复杂度内完成查找和插入操作  

4.4 Java8中HashMap链表使用红黑树而不是AVL树

在ConcurrentHashMap中是加了锁的,实际上是读写锁,如果写冲突就会等待,如果插入时间过长必然等待时间更长,而红黑树相对AVL树插入更快

4.5 既然红黑树那么好,为啥hashmap不直接采用红黑树,而是当大于8个的时候才转换红黑树

因为红黑树需要左旋、右旋操作,而单链表不需要  
以下都是单链表与红黑树结构对比  
如果元素小于8个,查询成本高,新增成本低  
如果元素大于8个,查询成本低,新增成本高  

4.6 红黑树应用实例

JAVA: java.util.TreeMap、java.utils.TreeSet   
C++ STL: map、multimap、multiset  
Linux内核: 完全公平的调度程序, linux/rbtree.h  

欢迎关注公众号算法小生第一时间获取更多精彩内容

  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

算法小生Đ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值