[golang] 数据结构-树形选择排序(锦标赛排序)

接上文 简单选择排序
简单选择排序很容易理解,代码也很容易实现。但毕竟比较次数太多。树形选择排序则对这个问题进行了改进。

原理
简单来说,树形选择排序(Tree selection sort)就是在选择完一轮找出最小值后,直接在与最小值比较中稍大的元素里筛选出最小的。这样避免了简单选择查询那种,抛弃了之前比较过的结果,每次都全部重新比较的情况。

流程举例

  • 先列出所有待排序的元素如:8、4、12、7、35、9、22,并用他们组成满二叉树的叶子元素,不足的位置以∞作为补充。
    将元素两两相比较,分别得到较小值:4,7,9,22。再次两两比较,得到4,9。最终比较一次得到最小值4。由此构建出一个完整的满二叉树:
  • 完成一轮比较后,将胜出者4的叶子节点改成∞,然后由它的兄弟节点8继续参加下一轮比较。从这次开始,元素8仅需按构建好的树结构一步步向上与其他胜出的非父节点仅需比较即可,比如这里只需要在和7,9比较,就能得到最小元素是7
  • 然后将元素7的叶子节点改成∞,其兄弟节点12与8、9节点比较,即可得到8:
  • 以此类推,最终得到最后一个元素35:

时间复杂度
由于每次仅需与胜出的其他节点仅需比较,所以时间复杂度相较简单选择排序的O(n^2)降低到O(nlogn)。
但是由于储存了每次各胜出节点的数据,所以需要更多的储存空间,而且其中n-1次的与∞的比较行为较为多余。

代码实现

package main

import (
    "fmt"
    "math"
)

// 声明一个节点的结构体,包含节点数值大小和是否需要参与比较
type node struct {
    // 数值大小
    value int
    // 叶子节点状态
    available bool
    // 叶子中的排序,方便失效
    rank int
}

func main() {
    var length = 10
    var mm = make(map[int]int, length)
    var o []int

    // 先准备一个顺序随机的数(qie)组(pian)
    for i := 0; i < length; i++ {
        mm[i] = i
    }
    for k, _ := range mm {
        o = append(o, k)
    }

    fmt.Println(o)
    treeSelectionSort(o)
}

func treeSelectionSort(origin []int) []int {
    // 树的层数
    var level int
    var result = make([]int, 0, len(origin))
    for pow(2, level) < len(origin) {
        level++
    }
    // 叶子节点数
    var leaf = pow(2, level)
    var tree = make([]node, leaf*2-1)

    // 先填充叶子节点的数据
    for i := 0; i < len(origin); i++ {
        tree[leaf+i-1] = node{origin[i], true, i}
    }
    // 每层都比较叶子兄弟大小,选出较大值作为父节点
    for i := 0; i < level; i++ {
        // 当前层节点数
        nodeCount := pow(2, level-i)
        // 每组兄弟间比较
        for j := 0; j < nodeCount/2; j++ {
            compareAndUp(&tree, nodeCount-1+j*2)
        }
    }

    // 这个时候树顶端的就是最小的元素了
    result = append(result, tree[0].value)
    fmt.Println(result)

    // 选出最小的元素后,还剩n-1个需要排序
    for t := 0; t < len(origin) - 1; t++ {
        // 赢球的节点
        winNode := tree[0].rank + leaf - 1
        // 把赢球的叶子节点状态改为失效
        tree[winNode].available = false

        // 从下一轮开始,只需与每次胜出节点的兄弟节点进行比较
        for i := 0; i < level; i ++ {
            leftNode := winNode
            if winNode%2 == 0 {
                leftNode = winNode - 1
            }

            // 比较兄弟节点间大小,并将胜出的节点向上传递
            compareAndUp(&tree, leftNode)
            winNode = (leftNode - 1) / 2
        }

        // 每轮都会吧最小的推到树顶端
        result = append(result, tree[0].value)
        fmt.Println(result)
    }

    return origin
}

func compareAndUp(tree *[]node, leftNode int) {
    rightNode := leftNode + 1

    // 除非左节点无效或者右节点有效并且比左节点大,否则就无脑选左节点
    if !(*tree)[leftNode].available || ((*tree)[rightNode].available && (*tree)[leftNode].value > (*tree)[rightNode].value) {
        (*tree)[(leftNode-1)/2] = (*tree)[rightNode]
    } else {
        (*tree)[(leftNode-1)/2] = (*tree)[leftNode]
    }
}

func pow(x, y int) int {
    return int(math.Pow(float64(x), float64(y)))
}

运行结果

原文地址:http://blog.51cto.com/13022101/2142664

时间: 2024-08-29 00:39:48

[golang] 数据结构-树形选择排序(锦标赛排序)的相关文章

[golang] 数据结构-简单选择排序

原理简单选择排序应该是最直观最容易理解的排序方法了.直接从头开始一个一个去比,找出最小的放到最左边.再依次完成其他位的排序. 时间复杂度比较次数固定为O(n^2),数据交换次数是0~n-1次因为会交换不同位置相同数值的数据,所以选择排序并不稳定 代码实现 package main import ( "fmt" ) func main() { var length = 10 var mm = make(map[int]int, length) var o []int // 先准备一个顺序

golang数据结构之选择排序

//SelectSort 选择排序 func SelectSort(arr *[7]int) { for i := 0; i < len(arr); i++ { tmp := arr[i] index := i for j := i + 1; j < len(arr); j++ { if (*arr)[j] < tmp { tmp = (*arr)[j] index = j } } if index != i { (*arr)[index], (*arr)[i] = (*arr)[i],

数据结构 - 树形选择排序 (tree selection sort) 详解 及 代码

http://blog.csdn.net/yj_1989/article/details/46598579http://blog.csdn.net/yj_1989/article/details/46598581http://blog.csdn.net/yj_1989/article/details/46598605http://blog.csdn.net/yj_1989/article/details/46598607http://blog.csdn.net/yj_1989/article/d

算法二之树形选择排序

一.树形选择排序的基本思想 (1) 树形选择排序又称锦标赛排序(Tournament Sort),是一种按照锦标赛的思想进行选择排序的方法.首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进行两两比较,如此重复,直至选出最小的记录为止. (2) 树形选择排序(Tree Selection Sort),这个过程可用一棵有n个叶子结点的完全二叉树表示. 例如,图表中的二叉树表示从8个数中选出最小数的过程. 8个叶子结点到根接点中的关键字,每个非终端结点中的数均等于其左右孩子结点中较小的

内部排序-&gt;选择排序-&gt;树形选择排序

文字描述 树形选择排序又称锦标赛排序; 比如,在8个运动员中决出前3名至多需要11场比赛, 而不是7+6+5=18场比赛(它的前提是甲胜乙,乙胜丙,则甲必能胜丙) 首先对n个记录的关键字进行两两比较,然后在(n/2)个较小者之间再进行两两比较,直至选出最小关键字的记录为止,这个过程可用一颗有n个叶子结点的完全二叉树表示.关于完全二叉树的定义和与本排序算法用到的性质见附录1 示意图 算法分析 由于含n个叶子结点的完全二叉树的深度为[log2n]+1, 则在树形选择排序中,除了最小关键字外,每选择一

数据结构 - 简单选择排序(simple selection sort) 详解 及 代码(C++)

数据结构 - 简单选择排序(simple selection sort) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/28601965 选择排序(selection sort) : 每一趟在n-i+1个记录中选取关键字最小的记录作为有序序列中第i个记录. 简单选择排序(simple selection sort) : 通过n-i次关键字之间的比较, 从n-i+1个记录中选出关键字最小的记录, 并和第i个记录交换. 选择排序需

一天一学数据结构之选择排序

每次 从待排序序列中选择出一个最大(或者最小)的记录添加到有序序列的后面即为选择排序. 选择排序主要有:简单选择排序.树形选择排序.堆排序. 1.简单选择排序 基本思路:重复进行n趟选择,第i趟通过n-i次记录的比较,在n-i+1个记录中选取最小(或最大)的记录与第i个记录进行交换. void selectSort(int arr[],int n){ int outer,inner; int min; for(outer=1;outer<=n;outer++ ){ min = outer; fo

【数据结构】选择排序算法示例

基本选择排序编辑 排序算法即解决以下问题的算法: 输入 n个数的序列<a1,a2,a3,...,an>. 输出 原序列的一个重排<a1*,a2*,a3*,...,an*>:,使得a1*<=a2*<=a3*<=...<=an* 排序算法有很多,包括插入排序,冒泡排序,堆排序,归并排序,选择排序,计数排序,基数排序,桶排序,快速排序等.插入排序,堆排序,选择排序,归并排序和快速排序,冒泡排序都是比较排序,它们通过对数组中的元素进行比较来实现排序,其他排序算法则是

数据结构与算法之——八大排序算法

附:关于这个主题,网上好的文章已经数不胜数,本篇是整合后的文章. 正文: 一.概述 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 本文所指八大排序就是内部排序. 当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序.堆排序或归并排序序. 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短: 二.排序算法详述 1.