java容器笔记+寻找最小的k个数+寻找数据流的中位数

容器的一些基本操作:
import java.util.*;
class Person implements Comparable<Person>{
    String name;
    int age;
    public Person (String name,int age) {
        this.name = name;
        this.age = age;
    }
    public Person(String name2, double d) {
        // TODO Auto-generated constructor stub
    }
    //要通过容器对插入的对象实例进行排序,必须在类的定义中实现比较器,且实现对应的接口
    public int compareTo(Person o) {
        return this.age - o.age;
    }
}
public class treeMapOrHashMap {
    public static void main(String[] args) {
        //https://www.cnblogs.com/yzssoft/p/7127894.html 
        TreeMap<String,Double> map11 = new TreeMap<>();
        map11.put("ccc",89.0); //必须双引号,单引号不行
        map11.put("kkk", 92.0);
        map11.put("aaa",28.0);
        System.out.println("map11"+map11);//容器是可以直接打印的,不用一个一个输出

        TreeSet<String> map12 = new TreeSet<>();
        map12.add("ccc"); //必须双引号,单引号不行
        map12.add("kkk");
        map12.add("aaa"); //上面是put
        System.out.println("map12"+map12);//容器是可以直接打印的,不用一个一个输出
        //说明treeMap是放键值对,treeSet是只能放一个数据对象(一般放字符串或者数字)
        //treeMap是按照键值进行升序排序的,treeSet也是默认排序的

        //如果要保存数据对象,则一般使用ArrayList,并且实现对应的接口,这样才知道怎么排序的
        ArrayList<Person> map22 = new ArrayList<Person>();
        //自己定义的数据对象,底层不知道怎么比,必须在定义的时候实现比较的借口
        map22.add(new Person("ccc",89)); //必须双引号,单引号不行
        map22.add(new Person("kkk", 92));
        map22.add(new Person("aaa",28));
        //还的调用下排序
        Collections.sort(map22);
        System.out.println("ArrayList排序后:");
        for(Person ss : map22) {
            System.out.println("name: "+ss.name+"age: "+ss.age);
        }
    }
}
寻找最小的k个数:
import java.util.*;
public class findKofMin {
    public ArrayList<Integer> solve(int[] arr,int k){
        ArrayList<Integer> list = new ArrayList<Integer>();
        if (arr.length < k ) return list;

        //使用大根堆来维护最小的k个数,通过TreeSet来代替大根堆,因为其是红黑树,
        //默认按照升序排列。如果用优先队列,还要自己实现比较器,且相同的数会保留下来。
        TreeSet<Integer> s = new TreeSet<>();
        for(int i = 0; i < arr.length; i++) {
            if(s.size()<k)
                s.add(arr[i]);
            else if(arr[i]<s.last()) {
                s.remove(s.last());
                s.add(arr[i]);
            }
        }
        //现在把红黑树的数转存到ArrayList中
        Iterator<Integer> it = s.iterator();
        while(it.hasNext()) {
            list.add(it.next());
        }
        return list;
    }
    public static void main(String[] args) {
        findKofMin aa = new findKofMin();
        int [] arr = {1,5,6,0,3,16,8,37};
        System.out.println(aa.solve(arr,4));
    }
}
寻找中位数:使用优先队列
import java.util.*;
public class findMidlleNum {
    int count = 0; //用来判断数据流吐出来的数是奇数还是偶数
    PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    //PriorityQueue优先队列底层是二叉小根堆实现的,所以弹出队列头部的数据是队列中最小的数据
    //上一道题寻找数组中的最小k个数,是用大根堆()通过treeSet实现(因为本身按照升序排列)
    //这里的使用优先队列是因为这里的数可能重复,若用treeSet就不合适,所以用优先队列
    //且本身优先队列就是通过小根堆实现的。此外,为了实现大小根堆,通过在其中加个比较器即可

    PriorityQueue<Integer> maxHeap = new PriorityQueue<>(15,  //容量
            new Comparator<Integer>() {
        public int compare(Integer o1,Integer o2){
            return o2 - o1; 
            //本来是o1过了o2,现在倒过来减,所以是优先弹出最大值,从而实现大根堆。
        }
    });
    /**
     * 剑指offer上的大体思路是:
     * 插入数据流:
     * 1.一个大根堆(堆顶元素比此堆中其他元素大),一个小根堆(堆顶元素比此堆中其他元素小)
     * 2.中位数左边的数一定比它小,右边的数一定 比它大。所以左边用大根堆找最大值比中位数小,右边用小根堆找最小值比中位数大。
     * 3.注意两个堆的大小不能超过1,所以只能一次放一个堆,且是交替放。
     * 4.因为先有小的再有大的,所以设定偶数放小根堆,奇数放大根堆。就拿第一次放数来看谁放谁。
     * 5.放的时候要保证小根堆的最小值比大根堆的最大值要大(即保证中位数的后半段比前半段都大),所以新进来的数放大根堆时
     * 一定是先放到小根堆找到最小值,然后弹出放到大根堆。若新进来的数要放小根堆也是同样的道理,
     * 先放到大根堆中,弹出堆顶再放到小根堆中。
     * 
     * 6.取中位数:若总数是偶数一定是两个根堆的平均值,若是奇数一定是小根堆中的堆顶。
     * */

    public void Insert(int num) {
        if(count % 2 == 0) {
            //说明要放后半段了,即小根堆,先进大根堆再弹出进小根堆
            maxHeap.add(num); //add 和offer方法都一样,只不过对容错的处理方式不同,一个是报错,一个返回false
            minHeap.add(maxHeap.poll());//poll和remove的区别同上
        }
        else {
            //说明进中位数的前半段(大根堆,因为找最大值),先进小根堆,弹出再进大根堆。
            minHeap.add(num);
            maxHeap.add(minHeap.poll());
        }
        count++;
    }

    public Double getMedian() {
        if(count%2==0) return new Double(minHeap.peek()+maxHeap.peek())/2.0;
        else return new Double(minHeap.peek());
    }

    public static void main(String[] args) {
        findMidlleNum aa = new findMidlleNum();
        aa.Insert(15);
        aa.Insert(5);
        aa.Insert(10);
        aa.getMedian();
        System.out.println(aa.getMedian());
    }
}

红黑树(平衡性较高),AVL树(平衡性高度严格,最高),’SB’树(平衡性适中,现在用的最多)都是搜索二叉树,只是他们的平衡性不同。越平衡的树,其越接近二分查找,每次丢弃一个数,所以查找效率高。但是一味地追求高平衡性会导致很多额外的调整操作,反而效率降低。平衡树的容器代表是TreeMap(基于红黑树实现),TreeSet是基于TreeMap修改得来,两者都是默认按照升序排列,一个是按照键值,一个是按照value。此外,hash也有类似的操作且速度很快,为什么发明这个呢?因为在一些反复的查找中,如得到 .firstkey()等操作中tree树的操作是优于hash函数的。

HashMap<String,Integer> hash = new HashMap<>();
HashSet<Integer> hash1 = new HashSet<>();
//和treemap和treeSet一样,一个只能存键值对,一个只能存单一的数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值