《数据结构》学习笔记(8)——面向排序的数据结构

版权声明:本文为博主原创,未经博主允许不得转载。 https://blog.csdn.net/weixin_36904568/article/details/88666727

一:堆

1:定义

堆是一棵完全二叉树,它的根结点是所有结点中最大或最小的,较大或较小的结点靠近根结点。

2:堆的分类

  • 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆。ki>=k2i+1,ki>=k2i
  • 每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。ki<=k2i+1,ki<=k2i

3:构造堆

  static int[] heap;  //存放堆

    //构造堆
    public static int[] build(int[] arr) {  //将数组一个个上浮到堆上
        heap = new int[arr.length + 1];
        for (int i = 0; i < arr.length; i++) {
            swim(i+1,arr[i]);
        }
        return heap;
    }

    //上浮
    public static void swim(int index,int key) {
        heap[index] = key;  //先将待检查的记录放入堆中
        while (index > 1 && heap[index] > heap[index/2]) {  //如果记录比根结点大,则需要上浮
            int max = index;
            if(index/2 == 1 && heap[index]<heap[index-1])   //找出需要上浮的结点或兄弟结点
                max = index - 1;
            SortUtil.swap(max,index /= 2,heap); //上浮
        }
    }

二:优先队列

1:定义:支持删除最大元素和增加元素的队列

2:抽象数据类型

  • MaxPQ(int max):创建一个最大容量为max的优先队列
  • MaxPQ(Key[] a) :用a[]中的元素创建一个优先队列
  • void Insert(Key v) :向优先队列中插人一个元素
  • Key max(): 返回最大元素
  • Key delMax(): 删除并返回最大兀素
  • boolean i sEmpty(): 返回队列是否为空
  • int size() 返回优先队列中的元素个数

3:存储结构

(1):使用数组


/**
 * 用数组实现优点队列
 */
public class ArrayPQ<T>  {
    //创建数组保存值
    private  T[] arr;
    //创建顶部指针
    private int N = 0;

    public ArrayPQ(int len){
        arr = (T[]) new Object[len];
    }

    public ArrayPQ(T[] array){
        arr = (T[]) new Object[array.length];
        for (int i = 0; i < array.length; i++) {
            arr[i] = array[i];
        }
    }

    public void resize(int max){
        T[] array = (T[]) new Object[max];
        array = Arrays.copyOf(arr,arr.length);
        arr = array;
    }

    //无序入栈,出栈时使用直接选择排序
    public void insert_notSorted(T element){
        if(N != arr.length)
            arr[N++] = element;
        else
            resize(arr.length*2);
    }

    //有序入栈,使用插入排序
    public void insert_sorted(T element){
        if(N != arr.length)
        {
            int i;
            for (i = N; i >0 && compareTo(arr[i-1],element) > 0; i--) {
                arr[i] = arr[i-1];
            }
            arr[i] = element;
            N++;
        }
        else
            resize(arr.length*2);
    }

    //取栈顶元素,直接选择排序
    public T max_notSorted(){
        if(N>0)
        {

            if(N > 0 && N == arr.length/4)
                resize(arr.length/2);
            int max = N-1;
            for (int i = 0; i < N - 1; i++) {
                if(compareTo(arr[max],arr[i]) < 0)
                    max = i;
            }
            if(max != N-1)
                swap(max,N-1);
            return arr[N-1];

        }
        else
            return null;
    }

    //取栈顶元素
    public T max_sorted(){
        if(N>0)
        {
            if(N > 0 && N == arr.length/4)
                resize(arr.length/2);
            return arr[N-1];

        }
        else
            return null;
    }

    //出栈,如果栈过大则压缩栈
    public T delMax_sorted() throws EmptyStackException {
        T maxKey = null;
        if(N>0)
        {
            maxKey = arr[N-1];
            arr[--N] = null;
            if(N > 0 && N == arr.length/4)
                resize(arr.length/2);
        }
        else
            throw new EmptyStackException();
        return maxKey;
    }


    //出栈,直接选择排序
    public T delMax_notSorted() throws EmptyStackException {
        T maxKey = null;
        if(N>0)
        {
            int max = N-1;
            for (int i = 0; i < N; i++) {
                if(compareTo(arr[max],arr[i]) < 0)
                    max = i;
            }
            if(max != N-1)
                swap(max,N-1);
            maxKey = arr[N-1];
            arr[--N] = null;
            if(N > 0 && N == arr.length/4)
                resize(arr.length/2);
        }
        else
            throw new EmptyStackException();
        return maxKey;
    }

    //是否为空栈
    public boolean isEmpty(){
        return N==0;
    }

    //栈的大小
    public int size(){
        return N;
    }

    //比较
    public int compareTo(T a,T b) {
        Class tClass = a.getClass();
        if(tClass == Integer.class)
        {
            if((Integer)a > (Integer)b)
                return 1;
            if((Integer)a == (Integer)b)
                return 0;
            return -1;
        }
        return a.toString().compareTo(b.toString());
    }
    //交换
    public void swap(int i, int j){
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

(2):使用链表


/**
 * 链表实现优先队列
 * @param <T>
 */
public class LinkedPQ<T> {
    //头结点
    private LinkNode<T> head;
    //链表长度
    private int size;

    public LinkedPQ() {
        head = new LinkNode<>();
        size = 0;
    }

    public LinkedPQ(T ele) {
        head = new LinkNode<>();
        LinkNode<T> node = new LinkNode<>(ele);
        head.setNext(node);
        size = 1;
    }

    public LinkedPQ(T[] array) {
        head = new LinkNode<>();
        LinkNode<T> node = new LinkNode<>(array[0]);
        head.setNext(node);
        LinkNode<T> temp = node;
        for (int i = 1; i < array.length; i++) {
            node = new LinkNode<>(array[i]);
            temp.setNext(node);
            temp = node;
        }
        size = array.length;
    }

    //获取链表长度
    public int getSize() {
        return size;
    }

    //判断链表是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    //无序入栈
    public void insert_notSorted(T ele) {
        LinkNode<T> temp = new LinkNode<>(ele);
        LinkNode<T> node = head.getNext();
        if (node != null)
            temp.setNext(node);
        head.setNext(temp);
        size++;
    }


    //有序入栈
    public void insert_sorted(T ele) {
        LinkNode<T> temp = new LinkNode<>(ele);
        LinkNode<T> node = head.getNext();
        while (node != null) {
            if (compareTo(node.getData(), ele) < 0)
                break;
            LinkNode<T> next = node.getNext();
            if (next == null) {
                node.setNext(temp);
                size++;
                return;
            }
            if (compareTo(next.getData(), ele) < 0)
            {
                node.setNext(temp);
                temp.setNext(next);
                size++;
                return;
            }
            node = node.getNext();
        }
        if (node != null)
            temp.setNext(node);
        head.setNext(temp);
        size++;
    }

    //有序出栈
    public LinkNode<T> delMax_sorted() {
        LinkNode<T> node = head.getNext();
        if (node != null) {
            LinkNode<T> temp = node.getNext();
            head.setNext(temp);
            size--;
        }
        return node;
    }

    //获取栈顶元素
    public LinkNode<T> max_sorted() {
        LinkNode<T> node = head.getNext();
        return node;
    }


    //无序出栈
    public LinkNode<T> delMax_notSorted() {
        LinkNode<T> node = head.getNext();
        LinkNode<T> max = node;
        LinkNode<T> prev = null;
        LinkNode<T> temp = null;
        if (node != null && node.getNext() == null) {
            head.setNext(node);
            size--;
        } else
        {
            while (node != null && node.getNext() != null) {
                temp = node.getNext();
                if (compareTo(max.getData(), temp.getData()) < 0) {
                    max = temp;
                    prev = node;
                }
                node = temp;
            }
            if(prev != null)
                prev.setNext(max.getNext());
            else
                head.setNext(max.getNext());
            size --;
        }

        return max;
    }

    //获取栈顶元素
    public LinkNode<T> max_notSorted() {
        LinkNode<T> node = head.getNext();
        LinkNode<T> max = node;
        while (node != null && node.getNext() != null) {
            LinkNode<T> next = node.getNext();
            if (compareTo(max.getData(), next.getData()) < 0)
                max = next;
            node = next;
        }
        return max;
    }


    //比较
    public int compareTo(T a, T b) {
        Class tClass = a.getClass();
        if (tClass == Integer.class) {
            if ((Integer) a > (Integer) b)
                return 1;
            if ((Integer) a == (Integer) b)
                return 0;
            return -1;
        }
        return a.toString().compareTo(b.toString());
    }
}

(3):使用堆


/**
 * 用堆实现优先队列
 */
public class HeapPQ<T> {
    private T[] heap;   //用堆存放队列
    private int size;   //记录堆的大小

    public HeapPQ(int len) {
            heap = (T[])new Object[len];
    }

    //构造堆
    public HeapPQ(T[] arr) {
        heap = (T[])new Object[arr.length + 1];
        for (int i = 0; i < arr.length; i++) {
            swim(i+1,arr[i]);
        }
    }


    //获取链表长度
    public int getSize() {
        return size;
    }

    //判断链表是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    //调整堆大小
    public void resize(int max){
        T[] array = (T[]) new Object[max];
        System.arraycopy(heap,1,array,1,size);
//        array = Arrays.copyOf(heap,heap.length);
        heap = array;
    }

    //插入
    public void insert(T key) {
        swim(size+1,key);
    }

    //获得最大值
    public T max(){
        return heap[1];
    }

    //删除最大值
    public T delMax(){
        T max = heap[1];
        swap(1,size,heap);
        heap[size--] = null;
        sink(1);
        return max;
    }

    //上浮
    public  void swim(int index,T key) {
        if(index > heap.length - 1)
            resize(heap.length*2);
        heap[index] = key;  //先将待检查的记录放入堆中
        size++;
        while (index > 1 && compareTo(heap[index],heap[index/2]) > 0) {  //如果记录比根结点大,则需要上浮
            int max = index;
            if(index/2 == 1 && compareTo(heap[index],heap[index - 1]) < 0)   //找出需要上浮的结点或兄弟结点
                max = index - 1;
            swap(max,index /= 2,heap); //上浮
        }
    }

    //下沉
    public  void sink(int key){
	    if(size > 0 && size == heap.length/4)
            resize(heap.length/2);       
        while (2 * key <= size) {    //在树的范围内找
            int j = 2 * key;
            if(j + 1 <= size && compareTo(heap[j],heap[j+1]) < 0) //找出较大的孩子
                j++;
            if(compareTo(heap[key],heap[j]) >= 0)     //如果根节点比较小就下沉
                break;
            swap(key,j,heap);
            key = j;
        }
    }

    //比较
    public int compareTo(T a, T b) {
        Class tClass = a.getClass();
        if (tClass == Integer.class) {
            if ((Integer) a > (Integer) b)
                return 1;
            if ((Integer) a == (Integer) b)
                return 0;
            return -1;
        }
        return a.toString().compareTo(b.toString());
    }

    public void swap(int i,int j,T[] arr){
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

三:索引优先队列:

可以用索引引用优先队列的元素,做出更改

1:抽象数据类型

  • IndexMinPQ(int maxN) 创建一个最大容量为maxN的优先队列,索引的取值范围为 0 至 maxN-1
  • void insert(int k, Item item) 插人一个元素,将它和索引k相关联
  • void change(int k, Item item) 将索引为k的元素素设为item
  • boolean contains(int k) 是否存在索引为k的元素
  • void delete(int k) 删去索引k及其相关联的元素
  • Item min() 返回最小元素
  • int minlndex() 返回最小元素的索引
  • int delMin() 删除最小元素并返回它的索引
  • boolean isEmptyO 优先队列是否为空
  • int size() 优先队列中的元素数量

2:实现

  1. 用一个数组记录索引对应的元素在树中的序号
  2. 用一个数组记录序号对应的元素索引
  3. 在调整元素时还要调整序号和索引
  4. 在删除元素时应该维护数组
public class IndexPQ<T> {
    private T[] heap;   //用堆存放队列
    private int size;   //记录堆的大小
    private int[] index;    //记录元素的索引在树中的位置序号
    private int[] indexInTree;   //记录树中序号对应的元素索引

    public IndexPQ(int len) {   //初始化堆和索引
        heap = (T[])new Object[len + 1];
        index = new int[len + 1];
        indexInTree = new int[len + 1];
        for (int i = 1; i < index.length; i++) {
            index[i] = -1;
        }
    }

    //构造堆
    public IndexPQ(T[] arr) {
        heap = (T[])new Object[arr.length + 1];
        index = new int[arr.length + 1];
        indexInTree = new int[arr.length + 1];
        for (int i = 0; i < arr.length; i++) {
            swim(i+1);
            index[i] = i+1;
            indexInTree[i] = i+1;
        }
    }


    //获取链表长度
    public int getSize() {
        return size;
    }

    //判断链表是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    //调整堆大小
    public void resize(int max){
        T[] array = (T[]) new Object[max];
        System.arraycopy(heap,1,array,1,size);
        heap = array;
    }


    //包含
    public boolean contains(int k){ 
        //判断索引中是否含有k
        if(k < 0 || k > index.length-1)
            return false;
        return index[k] != -1;
    }

    //获取索引k对应的元素
    public T get(int k){
        return heap[index[k]];
    }

    //获取索引k对应的序号
    public int getIndex(int k){
        return indexInTree[k];
    }

    //插入
    public void insert(int k,T key) {
        //判断索引是否在堆的界限内
        if(k < 0)   
            return;
        if(k > index.length - 1)
		  {
            resize(index.length*2);
            resize(indexInTree.length*2);
        }
        if(size+1 > heap.length - 1)
            resize(heap.length*2);
        //先将待检查的记录放入堆中,记录序号和索引
        size++;
        heap[size] = key;  
        index[k] = size;    
        indexInTree[size] = k; 
        //调整记录
        swim(size); 
    }

    //更改
    public void change(int k,T key){
        //判断索引是否在堆的界限内
        if(!contains(k))    
            insert(k,key);
        //确定索引k的元素在树中的序号,放入待调整的记录
        int treeIndex = index[k];   
        heap[treeIndex] = key;      
        //调整元素
        swim(treeIndex);            
        sink(treeIndex);            
    }

    //删除指定元素
    public void delete(int k){
        //判断索引是否在堆的界限内
        if(!contains(k))        
            return;
        int treeIndex = index[k];   //确定索引k的元素在树中的序号
        //把要删除的元素与最后一个元素交换,同时减小堆的个数
        swap(treeIndex,size--,heap);    
        //记得交换序号和索引
        SortUtil.swap(k,indexInTree[size+1],index);    
        SortUtil.swap(treeIndex,size+1,indexInTree);   
        //调整元素
        swim(treeIndex);                        
        sink(treeIndex);                        
        //释放结点,重新初始化结点的序号和索引
        heap[size+1] = null;        
        index[k] = -1;
        indexInTree[size+1] = -1;
    }


    //获得最大值
    public T max(){
        return heap[1];
    }

    //删除最大值
    public int delMax(){
        int maxIndex = indexInTree[1];  //获取最大值的索引
        //交换最大值和最后一个元素,同时减小堆
        swap(1,size--,heap);
        //记得交换序号和索引
        SortUtil.swap(maxIndex,indexInTree[size+1],index);  
        SortUtil.swap(1,size+1,indexInTree);    
        //下沉第一个元素
        sink(1);
        //释放结点并初始化索引和序号
        index[maxIndex] = -1;
        heap[size+1] = null;
        indexInTree[size+1] = -1;
        return maxIndex;
    }

    //返回最大值的索引
    public int maxIndex(){
        return indexInTree[1];
    }

    //上浮
    public  void swim(int index) {
        while (index > 1 && compareTo(heap[index],heap[index/2]) > 0) {  //如果记录比根结点大,则需要上浮
            int max = index;
            if(index/2 == 1 && compareTo(heap[index],heap[index - 1]) < 0)   //找出需要上浮的结点或兄弟结点
                max = index - 1;
            swap(max,index/2,heap); //上浮
            SortUtil.swap(max,index/2,this.index);
            SortUtil.swap(max,index/2,this.indexInTree);
            index /= 2;
        }
    }

    //下沉
    public  void sink(int key){
        if(size > 0 && size == heap.length/4)
            resize(heap.length/2);
        while (2 * key <= size) {    //在树的范围内找
            int j = 2 * key;
            if(j + 1 <= size && compareTo(heap[j],heap[j+1]) < 0) //找出较大的孩子
                j++;
            if(compareTo(heap[key],heap[j]) >= 0)     //如果根节点比较小就下沉
                break;
            swap(key,j,heap);
            SortUtil.swap(key,j,this.index);
            SortUtil.swap(key,j,this.indexInTree);
            key = j;
        }
    }

    //比较
    public int compareTo(T a, T b) {
        Class tClass = a.getClass();
        if (tClass == Integer.class) {
            if ((Integer) a > (Integer) b)
                return 1;
            if ((Integer) a == (Integer) b)
                return 0;
            return -1;
        }
        return a.toString().compareTo(b.toString());
    }

    public void swap(int i,int j,T[] arr){
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

猜你喜欢

转载自blog.csdn.net/weixin_36904568/article/details/88666727
今日推荐