堆排序及常见面试题

堆排序及常见面试题_第1张图片
⭐️前言⭐️

本篇文章记录堆排序以及对应的一些练习。

欢迎点赞 收藏留言评论 私信必回哟

博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

博客中涉及源码及博主日常练习代码均已上传GitHub


请添加图片描述

内容导读

  • 1.堆排序实现
  • 2.线段最大重合问题
  • 3.加强堆的实现

1.堆排序实现

实现思路:
1.首先先建大堆
2.建好堆后,利用堆的性质完成排序
3.将堆顶元素与堆位元素互换,那么堆尾位置元素就是堆中的最大元素,并将堆顶元素向下调整,继续保持堆结构。
4.持续相同操作,直到到堆顶位置,此时堆中元素变为升序。

代码实现:

public class HeapSort {
    public static void heapSort(int[] array) {
        createBigHeap(array);
        int end=array.length-1;
        while (end>=0) {
            swap(array,0,end);
            shiftDown(array,0,end);
            end--;
        }
    }
    
    private static void shiftDown(int[] array,int parent,int len) {
        // 保证有左孩子
        int child=2*parent+1;
        while (child<len) {
            // 如果有右孩子,左右孩子比较,child记录较大值的下标
            if(child+1<len&&array[child]<array[child+1]) {
                child++;
            }
            if(array[child]>array[parent]) {
                swap(array,child,parent);
                // 继续向下调整
                parent=child;
                child=2*parent+1;
            }else {
                break;
            }
        }
    }

    private static void swap(int[] array,int i,int j) {
        int tmp=array[i];
        array[i]=array[j];
        array[j]=tmp;
    }
    private static void createBigHeap(int[] array) {
        // 先找到最后一棵子树的父节点,让每棵子树成为大顶堆
        for(int parent=(array.length-1-1)/2;parent>=0;parent--) {
            shiftDown(array,parent,array.length);
        }
    }
}

2.线段最大重合问题

题目:
给定很多线段,每个线段都有两个数[start, end],
表示线段开始位置和结束位置,左右都是闭区间
规定:
1)线段的开始和结束位置一定都是整数值
2)线段重合区域的长度必须>=1
返回线段最多重合区域中,包含了几条线段

题解思路:
1.首先通过比较器,将所有线段基于线段的起始位置进行排序,然后来求每条线段的最大重复线段数。
2.利用小根堆(小根堆存储每条线段的结束位置),每次到达新线段时,将小根堆中比新线段起始位置小的数弹出(弹出的线段是起始位置和结束位置都比新线段其实位置小的线段,不可能有重复),并将新线段的结束位置放入小根堆,此时小根堆中代表的线段就是有公共重合区域的线段,返回heap.size()就是重复线段数。
3.每条线段都进行这样的操作,返回heap.size()中最大的max,就表示线段最多重合区域中,包含的线段数。

代码实现:

public class CoverMax {
    static class Line {
        public int start;
        public int end;

        public Line(int start, int end) {
            this.start = start;
            this.end = end;
        }
    }

    static int maxCover(int[][] m) {
        Line[] lines=new Line[m.length];
        for (int i = 0; i < m.length; i++) {
            lines[i]=new Line(m[i][0],m[i][1]);
        }
        Arrays.sort(lines, new Comparator<Line>() {
            @Override
            public int compare(Line o1, Line o2) {
                return o1.start-o2.start;
            }
        });
        // Arrays.sort(lines,(a,b)->a.start-b.start);  // 语法糖
        PriorityQueue<Integer> heap=new PriorityQueue<>();
        int max=0;
        for (int i = 0; i < lines.length; i++) {
            while (!heap.isEmpty()&&heap.peek()<=lines[i].start) {
                heap.poll();
            }
            heap.add(lines[i].end);
            max=Math.max(max,heap.size());
        }
        return max;
    }
}

3.加强堆的实现

是对于普通堆结构的改写,增添了一些普通堆不具有的功能

public class HeapGreater<T> {
    private ArrayList<T> heap;
    private HashMap<T,Integer> indexMap;  // 用于加强堆结构中的反向索引操作
    private int heapSize;
    private Comparator<? super T> comp;

    public HeapGreater(Comparator<? super T> comp) {
        heap=new ArrayList<>();
        indexMap=new HashMap<>();
        heapSize=0;
        this.comp = comp;
    }

    // 判断堆是否为空
    public boolean isEmpty() {
        return heapSize==0;
    }
    // 返回堆大小
    public int size() {
        return heapSize;
    }
    // 判断堆中是否包含某个元素
    public boolean contains(T obj) {
        return indexMap.containsKey(obj);
    }
    // 返回堆顶元素
    public T peek() {
        return heap.get(0);
    }
    // 堆中新增元素
    public void push(T obj) {
        heap.add(obj);
        indexMap.put(obj,heapSize);
        heapInsert(heapSize);
        heapSize++;
    }
    // 堆中插入新元素,向上调整新元素
    private void heapInsert(int child) {
        int parent=(child-1)/2;
        while (child>0) {
            if(comp.compare(heap.get(child),heap.get(parent))<0) {
                swap(child,parent);
                child=parent;
                parent=(child-1)/2;
            }else {
                break;
            }
        }
    }

    private void swap(int i, int j) {
        T o1=heap.get(i);
        T o2=heap.get(j);
        heap.set(i,o2);
        heap.set(j,o1);
        indexMap.put(o2,i);
        indexMap.put(o1,j);
    }
    // 弹出堆顶元素
    public T pop() {
        T ans=heap.get(0);
        swap(0,heapSize-1);
        indexMap.remove(ans);
        heap.remove(--heapSize);
        shiftDown(0);
        return ans;
    }
    // 小根堆向下调整
    private void shiftDown(int parent) {
        int child=2*parent+1;
        while (child<heapSize) {
            if(child+1<heapSize&&comp.compare(heap.get(child+1),heap.get(child))<0) {
                child++;
            }
            if(comp.compare(heap.get(child),heap.get(parent))<0) {
                swap(child,parent);
                parent=child;
                child=2*parent+1;
            }else {
                break;
            }
        }
    }
    // 去除某个元素
    public void remove(T obj) {
        T replace=heap.get(heapSize-1);
        int index=indexMap.get(obj);
        indexMap.remove(obj);
        heap.remove(--heapSize);
        if(obj!=replace) {
            heap.set(index,replace);
            indexMap.put(replace,index);
            resign(replace);
        }
    }

    private void resign(T obj) {
        heapInsert(indexMap.get(obj));
        shiftDown(indexMap.get(obj));
    }
    
    // 返回堆上所有元素
    public List<T> getAllElements() {
        List<T> ans=new ArrayList<>();
        for(T c:heap) {
            ans.add(c);
        }
        return ans;
    } 
}

⭐️最后的话⭐️
总结不易,希望uu们不要吝啬你们的哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正

请添加图片描述

你可能感兴趣的:(算法集锦,java,算法,数据结构)