В моем сердце куча

куча

博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收**藏 ^ _ ^ !

  1. В моем сердце куча https://blog.csdn.net/luo_boke/article/details/106928990
  2. В самом сердце есть дерево https://blog.csdn.net/luo_boke/article/details/106980011
  3. В моем сердце есть стек https://blog.csdn.net/luo_boke/article/details/106982563

Куча - это полное двоичное дерево , отсортированная древовидная структура данных, которая удовлетворяет следующим свойствам:

  1. Последовательность кучи: значение любого узла меньше (или больше) значения всех его потомков, а минимальный узел (или максимальный узел) находится в корне кучи.
  2. Структурный: куча всегда представляет собой полное двоичное дерево, то есть, за исключением нижнего слоя, узлы других слоев заполняются элементами, а нижний слой заполняется максимально слева направо.

Что такое бинарное дерево? Пожалуйста, проверьте мою другую запись в блоге "Дерево в основах сердца"

Маленькая корневая куча и большая корневая куча
Малая корневая куча: Куча, значение узла которой меньше значения узла-потомка, также называемая минимальной кучей, слева от рисунка
Большая корневая куча: Куча со значением узла, превышающим значение узла-потомка, также называемая самой большой кучей, справа от рисунка
Вставьте описание изображения сюда

Двоичная куча
Двоичная куча - это особый вид кучи, то есть каждый узел имеет не более двух дочерних узлов. Сортировка кучи - это используемая двоичная куча.

Хранилище кучи
обычно использует линейные структуры данных (например, массивы) для хранения кучи:
Вставьте описание изображения сюда

  • Корневой узел хранится в 0-й позиции
  • Левый дочерний элемент узла i хранится в 2 * i + 1
  • Правый дочерний элемент узла i хранится в 2 * i + 2

Процесс сборки кучи

1) Нажмите на родительский узел в соответствии с дочерним узлом: (n-1) / 2
2) Нажмите на дочерний узел в соответствии с родительским узлом: левый дочерний узел (2n + 1), правый дочерний узел (2n + 2)
индексирует 0 начинает отсчет

Мы строим большую корневую сваю с 10 числами 9, 12, 5, 24, 0, 1, 99, 3, 10, 7 следующим образом:

  1. Прежде всего, мы рассматриваем текущую неупорядоченную последовательность как структуру кучи, двоичное дерево без правил и заполняем двоичное дерево значениями в последовательности сверху вниз и слева направо.
    Вставьте описание изображения сюда
  2. Обойти родительский узел от последнего листа 7. Если родительский узел <максимального значения левого и правого дочерних узлов, значение родительского узла обменивается с максимальным дочерним узлом. Найдите, что 7 и 10 меньше 35, переключитесь на родительский узел 99 и 3, обнаружите, что 99> 24, поменяйте местами 24 и 99.
    Вставьте описание изображения сюда
  3. Продолжайте сравнивать родительские узлы 0 и 1, потому что 0 <5, 1 <5, спуститесь вниз, чтобы сравнить родительские узлы 99 и 35, самый большой дочерний узел 99> 12, поменяйте местами позиции. После обмена родительский узел 12 должен быть отсортирован, и обнаруживается, что 24> 12, а позиции 12 и 24 необходимо поменять местами.
    Вставьте описание изображения сюда
    Вставьте описание изображения сюда
  4. Продолжайте перемещаться по родительскому узлу 9, и вам нужно изменить позиции на 99. Точно так же 9 нуждается в самом большом дочернем узле 35 для изменения позиций.
    Вставьте описание изображения сюда
  5. Наконец-то получил много кода сборки root
    Вставьте описание изображения сюда

    /***
     * 构建大根堆
     * @param array  数据源
     */
    private void buildHeap(int[] array) {
    
    
        //从右向左,从下到上依次遍历父结点,建立大根堆,时间复杂度:O(n*log2n)
        for (int i = (array.length - 1 - 1) / 2; i >= 0; i--) {
    
    
            adjust(array, i, array.length - 1);
        }
    }
    
    /**
     * 将指定堆构建成大堆根函数
     * 逻辑
     * 1. 如果起始索引无子结点,则跳出该方法
     * 2. 如果只有一个左子结点,进行大小比较并置换值
     * 3. 如果有两个子结点,选择最大值与父结点比较,然后置换其位置。
     * 如果子结点大于父结点,置换完成后,递归进行同样操作,其子结点索引即是函数的start值
     *
     * @param array 源数组
     * @param start 起始索引
     * @param end   结尾索引
     */
    public void adjust(int[] array, int start, int end) {
    
    
        // 左子结点的位置
        int leftIndex = 2 * start + 1;
        if (leftIndex == end) {
    
    
            //只有一个左结点,进行比较并置换值
            if (array[leftIndex] > array[start]) {
    
    
                int temp = array[leftIndex];
                array[leftIndex] = array[start];
                array[start] = temp;
            }
        } else if (leftIndex < end) {
    
    
            //有两个子结点
            int temp = array[leftIndex];
            int tempIndex = leftIndex;
            if (array[leftIndex + 1] > array[leftIndex]) {
    
    
                temp = array[leftIndex + 1];
                tempIndex = leftIndex + 1;
            }
            if (temp > array[start]) {
    
    
                array[tempIndex] = array[start];
                array[start] = temp;
            }
            adjust(array, tempIndex, end);
        }
    }

Процесс сортировки кучи

Выше мы создали большую корневую кучу, и теперь мы сортируем кучу. Идея конструкции такая:

  1. Скомпилируйте в соответствии с характеристиками кучи, сначала создайте набор данных с n элементами в большую корневую кучу или маленькую корневую кучу (я ввожу его в соответствии с большой корневой кучей, и маленькая корневая куча - это та же идея).
  2. Затем поменяйте местами номер корневого узла с последней цифрой кучи.На данный момент n-я цифра является самым большим числом во всей последовательности.
  3. Затем сконструируйте первые n-1 как элементы, чтобы сформировать большую корневую кучу, а затем обменяйте корневой узел с данными n-1-го бита, чтобы получить вторые по величине данные.На данный момент последние два данных, несомненно, в порядке.
  4. Затем сформируйте первые n-2 данных в большую корневую кучу и выполняйте цикл до тех пор, пока не останется один элемент, указывая, что числа после первой цифры упорядочены и больше первой цифры, и сортировка завершена.
  • 1) Замените 99 на 7 и перестройте большую корневую кучу для кучи, которая исключает 99
    Вставьте описание изображения сюда
  • 2) Заменить позиции 35 и 9 и восстановить корни оставшихся 8 чисел.
    Вставьте описание изображения сюда
  • 3) Поменяйте местами 24 и 3 и восстановите большую корневую стопку для оставшихся 7 чисел
    Вставьте описание изображения сюда
  • 4) Последующий процесс тот же, и, наконец, получается отсортированная куча 0, 1, 3, 5, 7, 9, 10, 12, 24, 35, 99
    Вставьте описание изображения сюда

Сортировать код

    /**
     * 堆排序
     *
     * @param array 源数组
     */
    public void heapSort(int[] array) {
    
    
        buildHeap(array);
        int tmp;
        //要与root结点置换位置元素的索引
        int end = array.length - 1;
        //n个结点只用构建排序n-1次,最后只有1个元素不用在排序
        for (int i = array.length - 1; i > 0; i--) {
    
    
            tmp = array[0];
            array[0] = array[end];
            array[end] = tmp;

            end--;
            //头尾置换后,将堆重新构建为大堆根,置换尾部大元素不参加构建
            //因为除了root结点,其他都是由大到小有序的,所以再次构建大根堆时,不用在进行adjust()前的那个循环
            adjust(array, 0, end);
        }
    }

Элемент добавления кучи

При добавлении элементов новые элементы добавляются в конец массива, но после добавления элементов характер кучи может быть разрушен, и результат кучи необходимо скорректировать в сторону увеличения . Например, добавление элемента 100 в большую кучу корневых свай.
Вставьте описание изображения сюда
В это время структура сваи разрушена и ее нужно откорректировать снизу вверх. Поскольку 100 больше 0,5,99, новый корень
Вставьте описание изображения сюда
元素添加代码

    /**
     * 在 array 是大堆根的前提下添加元素然后重构大堆根
     *
     * @param array 大堆根数组
     * @param value 添加的元素值
     */
    private void addHeap(int[] array, int value) {
    
    
        int[] arr = new int[array.length + 1];
        System.arraycopy(array, 0, arr, 0, array.length);
        arr[arr.length - 1] = value;
        int currentIndex = arr.length - 1;
        int parentIndex = (arr.length - 1) / 2;
        while (parentIndex >= 0) {
    
    
            if (value > arr[parentIndex]) {
    
    
                int temp = arr[parentIndex];
                arr[parentIndex] = value;
                arr[currentIndex] = temp;

                //如果最后一个元素的父结点还有父结点需要继续进行对比
                currentIndex = parentIndex;
                parentIndex = (currentIndex - 1) / 2;
            } else {
    
    
                break;
            }
        }
    }

Элемент удаления кучи

Все элементы удаления кучи удаляются из узла, а затем последний элемент массива с этим узлом в качестве корневого узла перемещается в положение корневого узла, и структура кучи корректируется вниз, пока порядок кучи снова не будет соблюден. Если мы удалим узел 35, переместите 7 в позицию 35 и
Вставьте описание изображения сюда
сравните 7 с его дочерними узлами один за другим, пока он не будет соответствовать правилу большой корневой кучи.
Вставьте описание изображения сюда

Удалить код элемента

/**
     * 在 array 是大堆根的前提下删除元素然后重构大堆根
     *
     * @param array 大堆根数组
     * @param deleteIndex 删除元素的索引
     */
    private int[] deleteHeap(int[] array, int deleteIndex) {
    
    
        array[deleteIndex] = array[array.length - 1];
        int[] arr = new int[array.length - 1];
        System.arraycopy(array, 0, arr, 0, array.length - 1);
        int lefeIndex = 2 * deleteIndex + 1;
        while (lefeIndex >= arr.length - 1) {
    
    
            int maxIndex = lefeIndex;
            if (arr.length - 1 > lefeIndex) {
    
    
                if (arr[lefeIndex + 1] > arr[lefeIndex]) {
    
    
                    maxIndex = lefeIndex + 1;
                }
            }

            if (arr[maxIndex] > arr[deleteIndex]) {
    
    
                int temp = arr[maxIndex];
                arr[maxIndex] = arr[deleteIndex];
                arr[deleteIndex] = temp;
                lefeIndex = 2 * maxIndex + 1;
            } else {
    
    
                break;
            }
        }
        return arr;
    }

博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收**藏 ^ _ ^ !

Ссылки по теме

рекомендация

отblog.csdn.net/luo_boke/article/details/106928990