Двоичная куча, реализованная через бинарную древовидную структуру - PullRequest
2 голосов
/ 30 сентября 2011

Для назначения нам было поручено создать приоритетную очередь, реализованную через двоичную кучу, без использования каких-либо встроенных классов, и я успешно это сделал, используя массив для хранения объектов в очереди. Однако мне интересно узнать, как реализовать другую очередь, используя фактическую древовидную структуру, но при этом я столкнулся с небольшой проблемой.

Как я буду отслеживать узлы, на которых я буду выполнять вставку и удаление? Я попытался использовать связанный список, который добавляет каждый узел при его вставке - новые дочерние элементы добавляются начиная с первый узел списка и удален с противоположного конца. Однако, это разваливается, когда элементы переставляются в дереве, так как дочерние элементы добавляются в неправильной позиции.

Редактировать: Возможно, мне следует уточнить - я не уверен, как мне удастся найти последние занятые и первые незанятые листья. Например, я всегда мог бы сказать последний вставленный лист, но если бы я должен был удалить его, как бы я знал, какой лист удалить, когда я в следующий раз удаляю элемент? То же самое касается вставки - как я узнаю, к какому листу перейти к следующему после того, как на текущем листе учтены оба потомка?

Ответы [ 2 ]

1 голос
/ 30 сентября 2011

Древовидная реализация двоичной кучи использует полное дерево [или почти полное дерево: каждый уровень полон, кроме самого глубокого].
Вы всегда «знаете», какой последний занятый лист - где вы удаляете из [и изменяете его как O (logn) после того, как он изменился, так что это не проблема], и вы всегда «знаете», который является первым-Занятый лист, в котором вы добавляете элементы к [и снова изменяете их также O (logn) после того, как они изменились].

Идея алгоритма проста:
insert:вставьте элемент в первый незанятый лист и используйте heapify [sift up], чтобы этот элемент занял правильное место в куче.

delete_min: замените первый элемент последнимзанятый лист, и удалите последний занятый лист.затем сложите в кучу [откиньте вниз] кучу.

РЕДАКТИРОВАТЬ: обратите внимание, что delete() можно сделать с любым элементом, а не только с головой, - найдя элемент, который вы хотитезаменить на последний лист будет O (n), что сделает эту операцию дорогой.по этой причине метод delete() [помимо заголовка] обычно не является частью структуры данных кучи.

0 голосов
/ 19 августа 2016

Я действительно хотел сделать это в течение почти десятилетия. Наконец сел сегодня и написал это. Любой, кто хочет, может использовать это. Меня вдохновил основатель Quora, чтобы заново изучить Heap. Очевидно, его спросили, как бы вы нашли K рядом указывает на набор из n точек на экране своего телефона Google. Очевидно, его ответом было использование Max Heap и сохранение значений K и удаление максимального элемента после того, как размер кучи превысил K. Подход довольно прост и в худшем случае это nlog K, который лучше чем n ^ 2 в большинстве случаев сортировки. Вот код.

import java.util.ArrayList;
import java.util.List;

/**
 * @author Harish R
 */
public class HeapPractise<T extends Comparable<T>> {

    private List<T> heapList;

    public List<T> getHeapList() {
        return heapList;
    }

    public void setHeapList(List<T> heapList) {
        this.heapList = heapList;
    }

    private int heapSize;

    public HeapPractise() {
        this.heapList = new ArrayList<>();
        this.heapSize = heapList.size();
    }

    public void insert(T item) {
        if (heapList.size() == 0) {
            heapList.add(item);
        } else {
            siftUp(item);
        }

    }

    public void siftUp(T item) {
        heapList.add(item);
        heapSize = heapList.size();
        int currentIndex = heapSize - 1;
        while (currentIndex > 0) {
            int parentIndex = (int) Math.floor((currentIndex - 1) / 2);
            T parentItem = heapList.get(parentIndex);
            if (parentItem != null) {
                if (item.compareTo(parentItem) > 0) {
                    heapList.set(parentIndex, item);
                    heapList.set(currentIndex, parentItem);
                    currentIndex = parentIndex;
                    continue;
                }
            }
            break;
        }
    }

    public T delete() {
        if (heapList.size() == 0) {
            return null;
        }
        if (heapList.size() == 1) {
            T item = heapList.get(0);
            heapList.remove(0);
            return item;
        }
        return siftDown();
    }

    public T siftDown() {
        T item = heapList.get(0);
        T lastItem = heapList.get(heapList.size() - 1);
        heapList.remove(heapList.size() - 1);
        heapList.set(0, lastItem);
        heapSize = heapList.size();
        int currentIndex = 0;
        while (currentIndex < heapSize) {
            int leftIndex = (2 * currentIndex) + 1;
            int rightIndex = (2 * currentIndex) + 2;
            T leftItem = null;
            T rightItem = null;
            int currentLargestItemIndex = -1;
            if (leftIndex <= heapSize - 1) {
                leftItem = heapList.get(leftIndex);
            }
            if (rightIndex <= heapSize - 1) {
                rightItem = heapList.get(rightIndex);
            }
            T currentLargestItem = null;
            if (leftItem != null && rightItem != null) {

                if (leftItem.compareTo(rightItem) >= 0) {
                    currentLargestItem = leftItem;
                    currentLargestItemIndex = leftIndex;
                } else {
                    currentLargestItem = rightItem;
                    currentLargestItemIndex = rightIndex;
                }
            } else if (leftItem != null && rightItem == null) {
                currentLargestItem = leftItem;
                currentLargestItemIndex = leftIndex;
            }
            if (currentLargestItem != null) {
                if (lastItem.compareTo(currentLargestItem) >= 0) {
                    break;
                } else {
                    heapList.set(currentLargestItemIndex, lastItem);
                    heapList.set(currentIndex, currentLargestItem);
                    currentIndex = currentLargestItemIndex;
                    continue;
                }
            }
        }
        return item;

    }

    public static void main(String[] args) {
        HeapPractise<Integer> heap = new HeapPractise<>();

        for (int i = 0; i < 32; i++) {
            heap.insert(i);
        }
        System.out.println(heap.getHeapList());
        List<Node<Integer>> nodeArray = new ArrayList<>(heap.getHeapList()
                .size());
        for (int i = 0; i < heap.getHeapList().size(); i++) {
            Integer heapElement = heap.getHeapList().get(i);
            Node<Integer> node = new Node<Integer>(heapElement);
            nodeArray.add(node);
        }
        for (int i = 0; i < nodeArray.size(); i++) {
            int leftNodeIndex = (2 * i) + 1;
            int rightNodeIndex = (2 * i) + 2;
            Node<Integer> node = nodeArray.get(i);
            if (leftNodeIndex <= heap.getHeapList().size() - 1) {
                Node<Integer> leftNode = nodeArray.get(leftNodeIndex);
                node.left = leftNode;
            }
            if (rightNodeIndex <= heap.getHeapList().size() - 1) {
                Node<Integer> rightNode = nodeArray.get(rightNodeIndex);
                node.right = rightNode;
            }
        }
        BTreePrinter.printNode(nodeArray.get(0));
    }
}

public class Node<T extends Comparable<?>> {
    Node<T> left, right;
    T data;

    public Node(T data) {
        this.data = data;
    }
}

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class BTreePrinter {

    public static <T extends Comparable<?>> void printNode(Node<T> root) {
        int maxLevel = BTreePrinter.maxLevel(root);

        printNodeInternal(Collections.singletonList(root), 1, maxLevel);
    }

    private static <T extends Comparable<?>> void printNodeInternal(
            List<Node<T>> nodes, int level, int maxLevel) {
        if (nodes.isEmpty() || BTreePrinter.isAllElementsNull(nodes))
            return;

        int floor = maxLevel - level;
        int endgeLines = (int) Math.pow(2, (Math.max(floor - 1, 0)));
        int firstSpaces = (int) Math.pow(2, (floor)) - 1;
        int betweenSpaces = (int) Math.pow(2, (floor + 1)) - 1;

        BTreePrinter.printWhitespaces(firstSpaces);

        List<Node<T>> newNodes = new ArrayList<Node<T>>();
        for (Node<T> node : nodes) {
            if (node != null) {
                String nodeData = String.valueOf(node.data);
                if (nodeData != null) {
                    if (nodeData.length() == 1) {
                        nodeData = "0" + nodeData;
                    }
                }
                System.out.print(nodeData);
                newNodes.add(node.left);
                newNodes.add(node.right);
            } else {
                newNodes.add(null);
                newNodes.add(null);
                System.out.print("  ");
            }

            BTreePrinter.printWhitespaces(betweenSpaces);
        }
        System.out.println("");

        for (int i = 1; i <= endgeLines; i++) {
            for (int j = 0; j < nodes.size(); j++) {
                BTreePrinter.printWhitespaces(firstSpaces - i);
                if (nodes.get(j) == null) {
                    BTreePrinter.printWhitespaces(endgeLines + endgeLines + i
                            + 1);
                    continue;
                }

                if (nodes.get(j).left != null)
                    System.out.print("//");
                else
                    BTreePrinter.printWhitespaces(1);

                BTreePrinter.printWhitespaces(i + i - 1);

                if (nodes.get(j).right != null)
                    System.out.print("\\\\");
                else
                    BTreePrinter.printWhitespaces(1);

                BTreePrinter.printWhitespaces(endgeLines + endgeLines - i);
            }

            System.out.println("");
        }

        printNodeInternal(newNodes, level + 1, maxLevel);
    }

    private static void printWhitespaces(int count) {
        for (int i = 0; i < 2 * count; i++)
            System.out.print(" ");
    }

    private static <T extends Comparable<?>> int maxLevel(Node<T> node) {
        if (node == null)
            return 0;

        return Math.max(BTreePrinter.maxLevel(node.left),
                BTreePrinter.maxLevel(node.right)) + 1;
    }

    private static <T> boolean isAllElementsNull(List<T> list) {
        for (Object object : list) {
            if (object != null)
                return false;
        }

        return true;
    }

}

Обратите внимание, что BTreePrinter - это код, который я взял где-то в Stackoverflow давным-давно, и я изменил его для использования с 2-значными числами. Он будет сломан, если мы перейдем к 3-значным числам, и это только для простого понимания того, как структура кучи выглядит. Исправление для трехзначных чисел состоит в том, чтобы все было кратно 3. Также благодарность Сешу Венугопалу за прекрасный учебник на Youtube по структуре данных Heap

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...