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一樣,一個只能存鍵值對,一個只能存單一的數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章