通过指针的堆数据结构

Posted

技术标签:

【中文标题】通过指针的堆数据结构【英文标题】:heap data structure via pointers 【发布时间】:2017-03-27 23:24:58 【问题描述】:

提出一种在满足以下条件的堆中找到最后位置的有效方法:

1) 通过指针而不是通过数组

2) 我们可以在哪里插入或删除节点

我可以在 O(n) 时间复杂度中找到它,但建议使用 O(logn) 或 O(1) 时间复杂度的方法。

【问题讨论】:

这是作业吗?目前还不清楚你想要什么。如果你想有效地访问堆中的“最后一个位置”,你总是可以存储一个指向“最后一个元素”的指针。无论如何,插入到这个位置后,您需要再次合并堆,即将新元素冒泡。这有 O(logn) 复杂度 我在问你如何知道在哪里插入新数据,意味着 <br> 34 / \ 23 15 / \ / \ 20 13 让你拥有这个最大堆,你刚刚存储了13,现在你必须存储5,你将如何获得新位置的地址,你可以在哪里添加新节点(5)? 我们可以使用另一个堆吗? 尝试不使用另一个堆,如果你想使用另一个堆,请继续使用并建议你有什么新想法:) 【参考方案1】:

我在这里假设您的意思是二进制堆。

如果你知道堆中有多少个节点,你可以通过将计数转换为二进制,然后按照位从高到低的路径,在 O(log n) 时间内找到最后一个节点。即位为0取左节点,位为1取右节点。

例如,如果堆中有三个节点,则计数的二进制表示为 11。根始终是第一个节点,给你留下 1。然后你走右分支得到最后一个节点。

假设堆中有5个节点:

       1
    2     3
  4   5

在二进制中,即 101。所以你取根。下一个数字是 0,所以你选择左分支。下一个数字是 1,因此您选择右分支,将您留在节点 5。

如果您想要 下一个可用的 槽,则将计数加 1 并执行相同的操作。所以 6 是 110。你取根,然后是右分支,3 的左子节点是你要添加新节点的地方。

您可以对任何d-ary heap 做同样的事情,除了转换为base d 而不是转换为二进制。因此,如果您的堆节点每个都有最多三个子节点,您可以将计数转换为以 3 为底,并使用与上述基本相同的逻辑。

另一种方法是维护对堆中最后一个节点的引用,每次修改堆时更新它。或者,如果您想知道下一个节点将放置在哪里,您可以维护对没有两个子节点的第一个节点的引用。这是 O(1),但每次插入或删除都需要记账。

【讨论】:

为了维护对第一个没有两个孩子的节点的引用,我们需要找到它,这个查找步骤将花费至少 O(logn) 时间复杂度,所以每次插入和删除时间logn 会增加复杂性,我们将能够在 o(1) 中获得该位置,但这个 logn 时间已经添加。【参考方案2】:

我正在回答我自己的问题,在堆中插入时不需要跟踪下一个指针(通过指针堆),即使不需要跟踪父级,我正在为堆附加正在运行的 java 代码,所有可能的方法都包含在其中,getMin() = O(1), insert() = O(logn), extractMin = O(logn), reductionPriorityOfHead = O(logn),我已经为通用代码实现了它,所以它会也有助于理解通用概念。

  class MinHeap<E extends Comparable<E>> 

    private DoublyNode<E> root;
    private int size = 0;

    public DoublyNode<E> getRoot() 
        return root;
    

    public void setRoot(DoublyNode<E> root) 
        this.root = root;
    

    public int getSize() 
        return size;
    

    public void setSize(int size) 
        this.size = size;
    

    public MinHeap() 

    

    public MinHeap(E data) 
        this.root = new DoublyNode<E>(data);
        this.size++;
    

    private class NodeLevel<E extends Comparable<E>> 
        private int level;
        private DoublyNode<E> node;

        public int getLevel() 
            return level;
        

        public void setLevel(int level) 
            this.level = level;
        

        public DoublyNode<E> getNode() 
            return node;
        

        public void setNode(DoublyNode<E> node) 
            this.node = node;
        

        public NodeLevel(DoublyNode<E> node, int level) 
            this.node = node;
            this.level = level;
        

    

    public void insert(E data) 
        if (this.size == 0) 
            this.root = new DoublyNode<E>(data);
            this.size++;
            return;
        
        DoublyNode<E> tempRoot = this.root;
        Integer insertingElementPosition = this.size + 1;
        char[] insertingElementArray = Integer.toBinaryString(
                insertingElementPosition).toCharArray();
        DoublyNode<E> newNode = new DoublyNode<E>(data);
        int i;
        for (i = 1; i < insertingElementArray.length - 1; i++) 
            if (newNode.getData().compareTo(tempRoot.getData()) < 0) 
                this.swap(newNode, tempRoot);
            
            char c = insertingElementArray[i];
            if (c == '0') 
                tempRoot = tempRoot.getLeft();
             else 
                tempRoot = tempRoot.getRight();
            
        
        // newNode.setParent(tempRoot);
        if (newNode.getData().compareTo(tempRoot.getData()) < 0) 
            this.swap(newNode, tempRoot);
        
        if (insertingElementArray[i] == '0') 
            tempRoot.setLeft(newNode);
         else 
            tempRoot.setRight(newNode);
        
        this.size++;
    

    public void swap(DoublyNode<E> node1, DoublyNode<E> node2) 
        E temp = node1.getData();
        node1.setData(node2.getData());
        node2.setData(temp);
    

    public E getMin() 
        if (this.size == 0) 
            return null;
        
        return this.root.getData();
    

    public void heapifyDownWord(DoublyNode<E> temp) 
        if (temp == null) 
            return;
        
        DoublyNode<E> smallerChild = this.getSmallerChild(temp);
        if (smallerChild == null) 
            return;
        
        if (smallerChild.getData().compareTo(temp.getData()) < 0) 
            this.swap(temp, smallerChild);
            this.heapifyDownWord(smallerChild);
        
    

    public DoublyNode<E> getSmallerChild(DoublyNode<E> temp) 
        if (temp.getLeft() != null && temp.getRight() != null) 
            return (temp.getLeft().getData()
                    .compareTo(temp.getRight().getData()) < 0) ? temp.getLeft()
                    : temp.getRight();
         else if (temp.getLeft() != null) 
            return temp.getLeft();
         else 
            return temp.getRight();
        
    

    public E extractMin() 
        if (this.root == null) 
            return null;
        
        E temp = this.root.getData();
        if (this.root.getLeft() == null && this.root.getRight() == null) 
            this.root = null;
            this.size--;
            return temp;
        

        DoublyNode<E> parentOfLastData = this.getParentOfLastData();
        if (parentOfLastData.getRight() != null) 
            this.root.setData(parentOfLastData.getRight().getData());
            parentOfLastData.setRight(null);
         else 
            this.root.setData(parentOfLastData.getLeft().getData());
            parentOfLastData.setLeft(null);
        
        this.heapifyDownWord(this.root);
        return temp;
    

    public DoublyNode<E> getParentOfLastData() 
        if (this.size == 0) 
            return null;
        

        DoublyNode<E> tempRoot = this.root;
        Integer insertingElementPosition = this.size;
        char[] insertingElementArray = Integer.toBinaryString(
                insertingElementPosition).toCharArray();
        int i;
        for (i = 1; i < insertingElementArray.length - 1; i++) 
            char c = insertingElementArray[i];
            if (c == '0') 
                tempRoot = tempRoot.getLeft();
             else 
                tempRoot = tempRoot.getRight();
            
        
        return tempRoot;
    

    public DoublyNode<E> getParentOfLastEmptyPosition() 
        if (this.size == 0) 
            return null;
        

        DoublyNode<E> tempRoot = this.root;
        Integer insertingElementPosition = this.size + 1;
        char[] insertingElementArray = Integer.toBinaryString(
                insertingElementPosition).toCharArray();
        System.out.println(insertingElementArray.toString());
        int i;
        for (i = 1; i < insertingElementArray.length - 1; i++) 
            char c = insertingElementArray[i];
            if (c == '0') 
                tempRoot = tempRoot.getLeft();
             else 
                tempRoot = tempRoot.getRight();
            
        
        return tempRoot;
    

    public void print() 
        if (this.root == null) 
            System.out.println("Heap via pointer is empty!");
            return;
        
        System.out.println("\n Heap via pointer is:- ");
        Queue<NodeLevel<E>> dataQueue = new Queue<NodeLevel<E>>();
        Queue<Space> spaceQueue = new Queue<Space>();
        dataQueue.enQueue(new NodeLevel<E>(this.root, 1));
        int heightOfTree = this.getHeightOfHeap();
        Double powerHeghtBST = Math.pow(heightOfTree, 2);
        spaceQueue.enQueue(new Space(powerHeghtBST.intValue(), false));
        while (!dataQueue.isEmpty()) 
            Space space = spaceQueue.deQueue();
            NodeLevel<E> nodeLevel = dataQueue.deQueue();
            while (space.isNullSpace()) 
                space.printNullSpace();
                spaceQueue.enQueue(space);
                space = spaceQueue.deQueue();
            
            space.printFrontSpace();
            System.out.print(nodeLevel.getNode().getData().printingData());
            space.printBackSpace();
            if (nodeLevel.getNode().getLeft() != null) 
                dataQueue.enQueue(new NodeLevel<E>(nodeLevel.getNode()
                        .getLeft(), nodeLevel.getLevel() + 1));
                spaceQueue.enQueue(new Space(space.getSpaceSize() / 2, false));
             else 
                spaceQueue.enQueue(new Space(space.getSpaceSize() / 2, true));
            
            if (nodeLevel.getNode().getRight() != null) 
                dataQueue.enQueue(new NodeLevel<E>(nodeLevel.getNode()
                        .getRight(), nodeLevel.getLevel() + 1));
                spaceQueue.enQueue(new Space(space.getSpaceSize() / 2, false));
             else 
                spaceQueue.enQueue(new Space(space.getSpaceSize() / 2, true));
            
            if (!dataQueue.isEmpty()
                    && nodeLevel.getLevel() + 1 == dataQueue.getFrontData()
                            .getLevel()) 
                System.out.println("\n");
            
        
    

    public int getHeightOfHeap() 
        if (this.size == 0) 
            return 0;
        
        Double height = Math.log(this.size) / Math.log(2) + 1;
        return height.intValue();
    

    public void changePriorityOfHeapTop(E data) 
        if (this.root == null) 
            return;
        
        this.root.setData(data);
        this.heapifyDownWord(this.root);
    


interface Comparable<T> extends java.lang.Comparable<T> 

    /**
     * this methos returns a string of that data which to be shown during
     * printing tree
     * 
     * @return
     */
    public String printingData();


public class PracticeMainClass 

    public static void main(String[] args) 
        MinHeap<Student> minHeap1 = new MinHeap<Student>();
        minHeap1.insert(new Student(50, "a"));
        minHeap1.insert(new Student(20, "a"));
        minHeap1.insert(new Student(60, "a"));
        minHeap1.insert(new Student(30, "a"));
        minHeap1.insert(new Student(40, "a"));
        minHeap1.insert(new Student(70, "a"));
        minHeap1.insert(new Student(10, "a"));
        minHeap1.insert(new Student(55, "a"));
        minHeap1.insert(new Student(35, "a"));
        minHeap1.insert(new Student(45, "a"));
        minHeap1.print();
        minHeap1.getMin();
        minHeap1.print();
        System.out
                .println("\nminimum is:- " + minHeap1.getMin().printingData());
        minHeap1.print();
        System.out.println("\nminimum is:- "
                + minHeap1.extractMin().printingData());
        minHeap1.print();
        minHeap1.changePriorityOfHeapTop(new Student(75, "a"));
        minHeap1.print();
    


class DoublyNode<E extends Comparable<E>> 
    private E data;
    private DoublyNode<E> left;
    private DoublyNode<E> right;

    // private DoublyNode<E> parent;
    public DoublyNode() 

    

    public DoublyNode(E data) 
        this.data = data;
    

    public E getData() 
        return data;
    

    public void setData(E data) 
        this.data = data;
    

    public DoublyNode<E> getLeft() 
        return left;
    

    public void setLeft(DoublyNode<E> left) 
        this.left = left;
    

    public DoublyNode<E> getRight() 
        return right;
    

    public void setRight(DoublyNode<E> right) 
        this.right = right;
    
    // public DoublyNode<E> getParent() 
    // return parent;
    // 
    // public void setParent(DoublyNode<E> parent) 
    // this.parent = parent;
    // 



class Space 
    private boolean isNullSpace = false;
    private String frontSpace;
    private String backSpace;
    private String nullSpace;
    private int spaceSize;

    public boolean isNullSpace() 
        return isNullSpace;
    

    public void setNullSpace(boolean isNullSpace) 
        this.isNullSpace = isNullSpace;
    

    public int getSpaceSize() 
        return spaceSize;
    

    public void setSpaceSize(int spaceSize) 
        this.spaceSize = spaceSize;
    

    public Space(int spaceSize, boolean isNullSpace) 
        this.isNullSpace = isNullSpace;
        this.spaceSize = spaceSize;

        if (spaceSize == 0) 
            this.frontSpace = "";
            this.backSpace = "";
            this.nullSpace = "  ";
         else if (spaceSize == 1) 
            this.frontSpace = " ";
            this.backSpace = "";
            this.nullSpace = "    ";
         else if (spaceSize == 2) 
            this.frontSpace = "  ";
            this.backSpace = "";
            this.nullSpace = "    ";
         else 
            this.frontSpace = String.format("%" + (spaceSize) + "s", " ");
            this.backSpace = String.format("%" + (spaceSize - 2) + "s", " ");
            this.nullSpace = String.format("%" + 2 * (spaceSize) + "s", " ");

        
    

    public void printFrontSpace() 
        System.out.print(this.frontSpace);
    

    public void printBackSpace() 
        System.out.print(this.backSpace);
    

    public void printNullSpace() 
        System.out.print(this.nullSpace);
    



class Queue<E> 
    private Node<E> front;
    private Node<E> rear;
    private int queueSize = 0;

    public Queue() 

    

    public Queue(E data) 
        this.front = new Node(data);
        this.rear = this.front;
    

    public void enQueue(E data) 
        if (this.rear == null) 
            this.rear = new Node(data);
            this.front = this.rear;
         else 
            Node newNode = new Node(data);
            this.rear.setNext(newNode);
            this.rear = newNode;
        
        this.queueSize++;
    

    public E deQueue() 
        E returnValue;
        if (this.front == null) 
            return null;
         else if (this.front == this.rear) 
            returnValue = this.front.getData();
            this.front = null;
            this.rear = null;
         else 
            returnValue = this.front.getData();
            this.front = this.front.getNext();
        
        this.queueSize--;
        return returnValue;
    

    public void print() 
        Node temp = this.front;
        System.out.print("\n Queue is:-  ");
        if (temp == null) 
            System.out.println("  Empty! ");
        
        while (temp != null) 
            System.out.print(temp.getData() + ",");
            temp = temp.getNext();
        
    

    public int getQueueSize() 
        return queueSize;
    

    public E getFrontData() 
        if (this.front == null) 
            System.out.println("queue is empty!");
            return null;
        
        return this.front.getData();
    

    public E getRearData() 
        if (this.rear == null) 
            System.out.println("queue is empty!");
            return null;
        
        return this.rear.getData();
    

    public boolean isEmpty() 
        return this.front == null;
    


class Node<E> 
    private E data;
    private Node next;

    public Node(E data) 
        this.data = data;
    

    public E getData() 
        return data;
    

    public void setData(E data) 
        this.data = data;
    

    public Node getNext() 
        return next;
    

    public void setNext(Node next) 
        this.next = next;
    



class Student implements Comparable<Student> 
    private int id;
    private String name;

    @Override
    public int compareTo(Student student) 
        if (this.id == student.id) 
            return 0;
         else if (this.id < student.id) 
            return -1;
         else 
            return 1;
        
    

    public Student(int id, String name) 
        this.id = id;
        this.name = name;
    

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    @Override
    public String printingData() 
        // String printingData = " id: "+this.id+" name: "+this.name+" ";
        String printingData = String.valueOf(this.id);
        return printingData;
    


这段代码的输出是:-

Heap via pointer is:- 
                10              

        30              20      

    35      40      70      60  

  55  50  45
 Heap via pointer is:- 
                10              

        30              20      

    35      40      70      60  

  55  50  45
minimum is:- 10

 Heap via pointer is:- 
                10              

        30              20      

    35      40      70      60  

  55  50  45
minimum is:- 10

 Heap via pointer is:- 
                20              

        30              45      

    35      40      70      60  

  55  50
 Heap via pointer is:- 
                30              

        35              45      

    50      40      70      60  

  55  75

【讨论】:

很好的解决方案!!

以上是关于通过指针的堆数据结构的主要内容,如果未能解决你的问题,请参考以下文章

两个或多个线程如何在它们分配的堆上共享内存?

C 语言内存四区原理 ( 栈内存与堆内存对比示例 | 函数返回的堆内存指针 | 函数返回的栈内存指针 )

c语言函数能不能返回结构体

js中的堆和栈

5.3.5 堆

Linux 堆溢出原理分析