左式堆

作者: 月见樽 | 来源:发表于2018-03-27 21:30 被阅读0次

左式堆

性质

零路径长

零路径长的定义为:

零路径长:从节点X到一个没有两个子节点的(有一个子节点或没有子节点)节点的最短距离

对于零路径长,有以下递归的计算方法:

  • 每个节点的零路径长比子节点的最小零路径长大1
  • NULL的节点的零路径长为-1,只有一个子节点或没有子节点的节点零路径长为0

左式堆

左式堆是特殊的优先堆,除了有序性(每个节点的数据小于其子节点)以外,还有具有与零路径长相关的性质:对于左式堆,要求任一节点的左子节点零路径长大于等于右子节点的零路径长

操作

合并操作

左式堆的基本操作是合并,合并的递归描述如下:

  • 当输入的两个堆都是空的,输出空堆;当有一个堆是空的,则返回非空的堆
  • 当两个堆非空时,比较两个根节点的大小,返回为:
    • 堆根节点为原较小的根节点
    • 左子树为原较小的跟节点的左子树
    • 右子树为根节点较大的堆和跟节点较小堆右子树合并的结果

如下图所示:

merge_op.png

对于最终结果,可能在根节点上出现不符合左式堆的性质的情况,出现这种情况时,交换左右子节点即可:

merge_change.png

其他操作

有了核心操作合并,优先堆的其他操作可由合并实现:

  • 插入:通过合并单个节点和现有堆实现
  • 弹出:将根节点返回,并合并左右子堆

代码实现

节点数据结构体

type NodeData struct {
    data int
}

节点结构体

结构体

节点需要的特性有:

  • Num:优先级标记,数值越低优先级越高
  • Data:节点数据
  • Depth:零路径长度
  • Right和Left:左右子节点的指针
type Node struct {
    Num   int
    Data  NodeData
    Left  *Node
    Right *Node
    Depth int
}

节点方法

构造方法

func NewNode(Num int, Data NodeData) *Node {
    return &Node{Num, Data, nil, nil, 0}
}

获取零路径长

func (n *Node) GetDepth() int {
    if n.Left == nil && n.Right == nil {
        if n.Left.Depth > n.Right.Depth {
            n.Depth = n.Right.Depth + 1
            return n.Depth
        }
        n.Depth = n.Left.Depth + 1
        return n.Depth
    } else {
        n.Depth = 0
        return 0
    }
}

打印

func (n *Node) Print(indent string) {
    fmt.Println(indent, n.Num, n.Data)
    if n.Left != nil {
        n.Left.Print(indent + "\t")
    }
    if n.Right != nil {
        n.Right.Print(indent + "\t")
    }
}

左式堆结构

结构体

type LeftHeap struct {
    root *Node
}

方法

合并方法

func (l *LeftHeap) Merge(Node1 *Node, Node2 *Node) *Node {
    if Node1 == nil {
        return Node2
    } else if Node2 == nil {
        return Node1
    }
    Big, Small := Node1, Node2
    if Node1.Num < Node2.Num {
        Big, Small = Node2, Node1
    }
    if Small.Right == nil {
        Small.Right = Big
    } else {
        Small.Right = l.Merge(Small.Right, Big)
    }
    Small.GetDepth()
    return Small
}

调整方法

func (l *LeftHeap) Modify() {
    if l.root.Left == nil {
        if l.root.Right == nil {
            return
        } else {
            l.root.Left, l.root.Right = l.root.Right, l.root.Left
            return
        }
    } else if l.root.Right == nil {
        return
    }
    if l.root.Left.Depth < l.root.Right.Depth {
        l.root.Left, l.root.Right = l.root.Right, l.root.Left
    }
}

插入方法

func (l *LeftHeap) Push(InsertNum int, InsertData NodeData) {
    InsertNode := NewNode(InsertNum, InsertData)
    l.root = l.Merge(l.root, InsertNode)
    l.Modify()
}

弹出方法

func (l *LeftHeap) DeleteMin() (NodeData, error) {
    if l.root == nil {
        return NodeData{}, errors.New("empty heap")
    }
    returnData := l.root.Data
    l.root = l.Merge(l.root.Left, l.root.Right)
    l.Modify()
    return returnData, nil
}

打印方法

func (l *LeftHeap) Print() {
    l.root.Print("")
}

相关文章

  • 左式堆

    左式堆 性质 零路径长 零路径长的定义为: 零路径长:从节点X到一个没有两个子节点的(有一个子节点或没有子节点)节...

  • 左式堆合并的实现

    左式堆合并的实现 源自废弃的 csdn blog 分析 左式堆而言,较于小根堆合并速度快,O(n)链表比数组带来更...

  • 看图说话之左式堆(优先队列)——原理解析及java实现

    一丶左式堆的基本概念 数据结构之二叉堆(优先队列)——原理解析文章中介绍了二叉堆的基本原理。本文介绍左式堆的基本原...

  • 左式堆、斜堆、二项队列

    左式堆 设计一种堆结构像二叉堆那样高效地支持合并操作(即以 时间处理一次 Merge)而且只使用一个数组似乎很困难...

  • 【数据结构】堆(优先队列):二叉堆、d堆、左式堆、斜堆与二项队列

    这是数据结构类重新复习笔记的第 五 篇,同专题的其他文章可以移步:https://www.jianshu.com/...

  • 左骑马式

    屈双膝,双手放在双脚的两侧,撤右脚向后一大步,来到左骑马式; 调整前后距离三倍肩宽,左右距离与臀同宽; 右脚的前脚...

  • 左新月式

    请大家站在垫子前端,约一个横向脚掌的距离。屈双膝,双手放于双脚两侧。 撤右脚向后一大步,右膝点地。小腿、脚背伸展后...

  • 左骑马式

    屈双膝,双手放在双脚的两侧,撤右脚向后一大步,来到左骑马式; 调整前后距离三倍肩宽,左右距离与臀同宽; 右脚的前脚...

  • 促销方式

    堆立式促销 降价式促销 打折式促销

  • SQL连接

    1、内连接:显式、隐式(两个表中关联字段相同的数据)显示: 隐式: 2、外连接:左外链接、右外连接a、左外连接:(...

网友评论

    本文标题:左式堆

    本文链接:https://www.haomeiwen.com/subject/lxcecftx.html