随时找到数据流的中位数

问题

一、解题思路

解法

二、具体代码

import java.util.*;
//随时找到数据流的中位数
public class FindMidNum{

     //利用大、小根堆法解决
    private MyHeap<Integer>minHeap;  //小根堆
    private MyHeap<Integer>maxHeap;  //大根堆

    //构造函数实现初始化
    public FindMidNum(){
        this.maxHeap=new MyHeap<Integer>(new maxHeapComparator());
        this.minHeap=new MyHeap<Integer>(new minHeapComparator());
    }

    //向数据空间增加数
    public  void addNumber(Integer num){

         if(this.maxHeap.isEmpty()){
            this.maxHeap.add(num);
            return;
         }
         if(this.maxHeap.getHead()>=num){
            this.maxHeap.add(num);
         }else{

            if(this.minHeap.isEmpty()){
                 this.minHeap.add(num);
                 return;
            }
            if(this.minHeap.getHead()>num){
                 this.maxHeap.add(num);
            }else{
                 this.minHeap.add(num);
            }
         }
         this.modifyTwoHeapsSize();
    }

    //获得中位数
    public Integer getMedian(){

          long maxHeapSize=this.maxHeap.getSize();
          long minHeapSize=this.minHeap.getSize();
          if(maxHeapSize+minHeapSize==0){
              return null;
          }
          Integer  maxHeapHead=this.maxHeap.getHead(); //获得大根堆堆顶的元素
          Integer  minHeapHead=this.minHeap.getHead(); //获得小根堆堆顶的元素
          if(((maxHeapSize+minHeapSize)&1)==0){
               return (maxHeapHead+minHeapHead)/2;
          }else if(maxHeapSize>minHeapSize){
               return maxHeapHead;
          }else{
               return minHeapHead;
          }
    }

    //调整两个堆的大小
    private void modifyTwoHeapsSize(){
           if(this.maxHeap.getSize()==this.minHeap.getSize()+2){
                this.minHeap.add(this.maxHeap.popHead());
           }
           if(this.minHeap.getSize()==this.maxHeap.getSize()+2){
                this.maxHeap.add(this.minHeap.popHead());
           }
    }

   //获得随机的数组
    public static int[] getRandomArray(int maxLen, int maxValue) {
        int[] res = new int[(int) (Math.random() * maxLen) + 1];
        for (int i = 0; i != res.length; i++) {
            res[i] = (int) (Math.random() * maxValue);
        }
        return res;
    }

    // for test, this method is ineffective but absolutely right
    public static int getMedianOfArray(int[] arr) {
        int[] newArr = Arrays.copyOf(arr, arr.length);
        Arrays.sort(newArr);
        int mid = (newArr.length - 1) / 2;
        if ((newArr.length & 1) == 0) {
            return (newArr[mid] + newArr[mid + 1]) / 2;
        } else {
            return newArr[mid];
        }
    }

    public static void printArray(int[] arr) {
        for (int i = 0; i != arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
    public static void main(String[]args){
        System.out.println("Hello");
        //实例化对象
        boolean err = false;
        int testTimes = 20;
        for (int i = 0; i != testTimes; i++) {
            int len = 30;
            int maxValue = 1000;
            int[] arr = getRandomArray(len, maxValue);
            FindMidNum findMid=new FindMidNum(); 
            for (int j = 0; j != arr.length; j++) {
                //System.out.println(arr[j]);
                findMid.addNumber(arr[j]);
            }
            if (findMid.getMedian() != getMedianOfArray(arr)) {
                err = true;
                printArray(arr);
                break;
            }
        }

    }
}

//生成大根堆的比较器
class maxHeapComparator implements Comparator<Integer>{
          @Override
          public int compare(Integer o1,Integer o2){
               if(o2>o1){
                  return 1;
               }else{
                  return -1;
               }
          }
    }
  //生成小根堆的比较器
class minHeapComparator implements Comparator<Integer>{
          @Override
          public int compare(Integer o1,Integer o2){
               if(o2<o1){
                  return 1;
               }else{
                  return -1;
               }
          }
    }
//*****************************************************************
//定义自己的堆结构(可变存储堆的设计)
class MyHeap<K> {
        private Node<K> head; // heap head node
        private Node<K> last; // heap last node
        private long size; // heap size
        private Comparator<K> comp; // max-heap or min-heap

        public MyHeap(Comparator<K> compare) {
            head = null;
            last = null;
            size = 0;
            comp = compare; // max-heap or min-heap based on your Comparator
        }

        public K getHead() {
            return head == null ? null : head.value;
        }

        public long getSize() {
            return size;
        }

        public boolean isEmpty() {
            return size == 0 ? true : false;
        }

        // add a new node to heap
        public void add(K value) {
            Node<K> newNode = new Node<K>(value);
            if (size == 0) {
                head = newNode;
                last = newNode;
                size++;
                return;
            }
            Node<K> node = last;
            Node<K> parent = node.parent;
            // find right position to insert new node
            while (parent != null && node != parent.left) {
                node = parent;
                parent = node.parent;
            }
            Node<K> nodeToAdd = null;
            if (parent == null) {
                nodeToAdd = mostLeft(head);
                nodeToAdd.left = newNode;
                newNode.parent = nodeToAdd;
            } else if (parent.right == null) {
                parent.right = newNode;
                newNode.parent = parent;
            } else {
                nodeToAdd = mostLeft(parent.right);
                nodeToAdd.left = newNode;
                newNode.parent = nodeToAdd;
            }
            last = newNode;
            // heap insertion modify
            heapInsertModify();
            size++;
        }

        public K popHead() {
            if (size == 0) {
                return null;
            }
            Node<K> res = head;
            if (size == 1) {
                head = null;
                last = null;
                size--;
                return res.value;
            }
            Node<K> oldLast = popLastAndSetPreviousLast();
            // if after pop last node, the size of heap is 1
            if (size == 1) {
                head = oldLast;
                last = oldLast;
                return res.value;
            }
            // if after pop last node, the size of heap is larger than 1
            Node<K> headLeft = res.left;
            Node<K> headRight = res.right;
            oldLast.left = headLeft;
            if (headLeft != null) {
                headLeft.parent = oldLast;
            }
            oldLast.right = headRight;
            if (headRight != null) {
                headRight.parent = oldLast;
            }
            res.left = null;
            res.right = null;
            head = oldLast;
            // heap heapify process
            heapify(oldLast);
            return res.value;
        }

        // find the most left node of subtree which node is head
        private Node<K> mostLeft(Node<K> node) {
            while (node.left != null) {
                node = node.left;
            }
            return node;
        }

        // find the most right node of subtree which node is head
        private Node<K> mostRight(Node<K> node) {
            while (node.right != null) {
                node = node.right;
            }
            return node;
        }

        // heap insertion process
        private void heapInsertModify() {
            Node<K> node = last;
            Node<K> parent = node.parent;
            if (parent != null && comp.compare(node.value, parent.value) < 0) {
                last = parent;
            }
            while (parent != null && comp.compare(node.value, parent.value) < 0) {
                swapClosedTwoNodes(node, parent);
                parent = node.parent;
            }
            if (head.parent != null) {
                head = head.parent;
            }
        }

        // heap heapify process
        private void heapify(Node<K> node) {
            Node<K> left = node.left;
            Node<K> right = node.right;
            Node<K> most = node;
            while (left != null) {
                if (left != null && comp.compare(left.value, most.value) < 0) {
                    most = left;
                }
                if (right != null && comp.compare(right.value, most.value) < 0) {
                    most = right;
                }
                if (most != node) {
                    swapClosedTwoNodes(most, node);
                } else {
                    break;
                }
                left = node.left;
                right = node.right;
                most = node;
            }
            if (node.parent == last) {
                last = node;
            }
            while (node.parent != null) {
                node = node.parent;
            }
            head = node;
        }

        // swap two nodes in tree, and those two nodes are closed
        private void swapClosedTwoNodes(Node<K> node, Node<K> parent) {
            if (node == null || parent == null) {
                return;
            }
            Node<K> parentParent = parent.parent;
            Node<K> parentLeft = parent.left;
            Node<K> parentRight = parent.right;
            Node<K> nodeLeft = node.left;
            Node<K> nodeRight = node.right;
            node.parent = parentParent;
            if (parentParent != null) {
                if (parent == parentParent.left) {
                    parentParent.left = node;
                } else {
                    parentParent.right = node;
                }
            }
            parent.parent = node;
            if (nodeLeft != null) {
                nodeLeft.parent = parent;
            }
            if (nodeRight != null) {
                nodeRight.parent = parent;
            }
            if (node == parent.left) {
                node.left = parent;
                node.right = parentRight;
                if (parentRight != null) {
                    parentRight.parent = node;
                }
            } else {
                node.left = parentLeft;
                node.right = parent;
                if (parentLeft != null) {
                    parentLeft.parent = node;
                }
            }
            parent.left = nodeLeft;
            parent.right = nodeRight;
        }


        // pop last node in Tree, and set last to previous last node
        private Node<K> popLastAndSetPreviousLast() {
            Node<K> node = last;
            Node<K> parent = node.parent;
            while (parent != null && node != parent.right) {
                node = parent;
                parent = node.parent;
            }
            if (parent == null) {
                node = last;
                parent = node.parent;
                node.parent = null;
                if (node == parent.left) {
                    parent.left = null;
                } else {
                    parent.right = null;
                }
                last = mostRight(head);
            } else {
                Node<K> newLast = mostRight(parent.left);
                node = last;
                parent = node.parent;
                node.parent = null;
                if (node == parent.left) {
                    parent.left = null;
                } else {
                    parent.right = null;
                }
                last = newLast;
            }
            size--;
            return node;
        }

        // for test
        public void changeHead(K value) {
            if (this.head != null) {
                Node<K> newNode = new Node<K>(value);
                Node<K> headLeft = this.head.left;
                Node<K> headRight = this.head.right;
                if (headLeft != null) {
                    headLeft.parent = newNode;
                    newNode.left = headLeft;
                }
                if (headRight != null) {
                    headRight.parent = newNode;
                    newNode.right = headRight;
                }
                this.head.left = null;
                this.head.right = null;
                this.head = newNode;
                this.heapify(this.head);
            }
        }

        // (层次遍历)
        public void printHeapByLevel() {
            if (this.size == 0) {
                System.out.println("Heap Empty!");
                return;
            }
            System.out.println("Head: " + this.head.value);
            System.out.println("Last: " + this.last.value);
            System.out.println("Size: " + this.size);
            printBinaryTreeByDepth(this.head);
        }

        // (深度遍历)
        private void printBinaryTreeByDepth(Node<K> head) {
            Queue<Node<K>> nodeQueue = new LinkedList<Node<K>>();
            Node<K> levelLastNode = head;
            Node<K> nextLevelLastNode = null;
            int levelNum = 0;
            nodeQueue.add(head);
            System.out.print("Level 0 nodes: ");
            while (!nodeQueue.isEmpty()) {
                Node<K> current = nodeQueue.poll();
                System.out.print(current.value + " ");
                if (current.left != null) {
                    nextLevelLastNode = current.left;
                    nodeQueue.add(current.left);
                }
                if (current.right != null) {
                    nextLevelLastNode = current.right;
                    nodeQueue.add(current.right);
                }
                if (current == levelLastNode) {
                    levelLastNode = nextLevelLastNode;
                    nextLevelLastNode = null;
                    System.out.println();
                    if (levelLastNode != null) {
                        System.out.print("Level " + (++levelNum) + " nodes: ");
                    }
                }
            }
        }

    }

    // 定义对象的比较
 class MyComparator implements Comparator<Integer> {
        @Override
        public int compare(Integer o1, Integer o2) {
            if (o2 > o1) {
                return 1;
            } else {
                return -1;
            }
        }
    }
// binary tree node contains parent reference(包含指向父类二叉树)
class Node<K> {
        public K value;
        public Node<K> left;
        public Node<K> right;
        public Node<K> parent;

        public Node(K data) {
            value = data;
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值