go语言堆排序1

go 语言笔记heap:

// 最小/大堆排序,以及入堆出堆与删除        //删除空白行:^[ \t]*\n
//根结点为0,左子节点角标为2*k+1,右子节点角标为2*k+2,父节点角标为(k-1)/2
//如果只需要排序输出的话,只需要down()和Pop即可
// 最大堆只需要修改less函数即可
//主要堆的method包括: 入堆Push()、出堆Pop()、向上搜索定位的up()、向下搜索定位的down()、删除元素的Remove()
//主要函数:方便大小堆转换的less()、和两值交换的swap()、以及main
// 注意go中所有参数转递都是值传递// 所以要让h的变化在函数外也起作用,此处得传指针
package mainimport "fmt"
type Heap []int

func (h Heap) swap(i, j int) {    	   
    h[i], h[j] = h[j], h[i]   
}
//单独定义出来时为了方便大小堆排序的转换,当前小堆根排序转换成大堆根,只需要将"<"改成">"
func (h Heap) less(i, j int) bool {    
    return h[i] < h[j]     
}

//h.Push()入堆,从树的末梢入堆,并使用up来向上搜索定位入堆值的位置
func (h *Heap) Push(x int) {          
    *h = append(*h, x)      
    h.up(len(*h) - 1)   
}

//h.up()向上搜索定位入堆值h(i)的位置,需要与父节点比较,和他的兄弟结点无关,
func (h Heap) up(i int) {    
    for {       
         f := (i - 1) / 2 // 父亲结点        
         if i == f || h.less(f, i) {  //循环结束条件,h(i)为根结点,或者大于父结点            
         break       
         }       
     h.swap(f, i)  //交换当前值h(i)与父结点h(f)的值        
     i = f    //交换指针,将当前值上升到父结点那层,并进入到下一次的循环,直到达到循环结束条件     
     }
 }
 
//h.down() 向下搜索定位当前值h(i)的位置,传入当前结点,
//并将其与左右子结点的较小值进行比较,当大于较小值时,交换,并进入下一层循环
func (h Heap) down(i int) {     
    for {        
        l := 2*i + 1    // 得到当前值的左结点        
    if l >= len(h) {            
        break       //循环结束条件1:h(i)没有左右结点时,即此时h(i)已经是叶子结点了        
    }        
    j := l        //将左结点给j,j记为左右结点的较小值        
    if r := l + 1; r < len(h) && h.less(r, l) {            
        j = r          
    }        
    if h.less(i, j) {            
        break      // 环结束条件2:如果父结点比孩子结点小,则不交换          
    }        
    h.swap(i, j) // 如果父结点比子结点大,则交换父结点和最小的子结点        
    i = j        //继续向下比较,进行下一个循环,直到满足结束条件    
    }
}

// h.Remove() 删除堆中位置为i的元素
//思路:用最后一个值将待删除值替换,再对删除位置的最后一个值从新进行搜索定位排序
func (h *Heap) Remove(i int) (int, bool) {    
    if i < 0 || i > len(*h)-1 {   //判断删除值下标的有效性,下标在(0,len(*h)-1)之间        
        return 0, false    
    }    
    n := len(*h) - 1  //用于替换后丢弃删除的值    
    h.swap(i, n)    // 用最后的元素值替换被删除元素    
    // 删除最后的元素    
    x := (*h)[n]   //x为待删除值   
    *h = (*h)[0:n]      
   // 如果当前元素大于父结点,满足小堆根排序,则向下筛选    
   if (*h)[i] > (*h)[(i-1)/2] {        
       h.down(i)    
   } else { // 当前元素小于父结点,不满足小堆根排序,向上筛选       
        h.up(i)    
    }    
    return x, true
}

// 弹出堆顶的元素,并返回其值,
func (h *Heap) Pop() int {    
    n := len(*h) - 1    
    h.swap(0, n)    
    x := (*h)[n]    
   *h = (*h)[0:n]      
    h.down(0)    //弹出堆顶元素后需要从根部重新排序    
    return x
}

func main() {    
    var h = Heap{20, 7, 3, 10, 15, 25,30, 1, 17, 19}  //9个    
    n := len(h)    //通过h.down()将h按照小根堆排序    
    //这里不能直接h.down(0),而是需要从最后一个父结点开始,依次循环直到h.down(0)    
    for i := (n - 1)/2; i >= 0; i-- {          
        h.down(i)       
    }
    //h.down(0)       //从下标为0的根结点开始    
    fmt.Println(h)     // [1 7 3 10 15 25 30 20 17 19]
    h.Push(6)     //入堆    
    fmt.Println(h)    // [1 6 3 10 7 25 30 20 17 19 15]
    x, ok := h.Remove(5)    //删除下标是5的值,返回删除的值x,和删除true/false?    
    fmt.Println(x, ok, h)  // 25 true [1 6 3 10 7 15 30 20 17 19]
    y, ok := h.Remove(1)    
    fmt.Println(y, ok, h)      // 6 true [1 7 3 10 19 15 30 20 17]
    z := h.Pop()     //出堆    
    fmt.Println(z, h)       // 1 [3 7 15 10 19 17 30 20]        
    //升序输出---将最小的值依次pop出来存入数组并输出    
    var fh []int    
    for len(h) > 0 {        
        z := h.Pop()         
        fh = append(fh, z)    
    }    
    fmt.Println(fh)    // [3 7 10 15 17 19 20 30]
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值