zoukankan      html  css  js  c++  java
  • Hark的数据结构与算法练习之锦标赛排序

    算法说明

    锦标赛排序是选择排序的一种。

    实际上堆排序是锦标赛排序的优化版本,它们时间复杂度都是O(nlog2n),不同之处是堆排序的空间复杂度(O(1))远远低于锦标赛的空间复杂度(O(2n-1))

    堆排序是基于二叉树的, 所以锦标赛排序也是基于二叉树的,并且是完美二叉树。

    我尝试用最通俗的方法来做一下解释,如果我说的不大清楚,建议大家直接看下边的代码啦。

    1、例如我们要对int[] arrayData = { 5, 9, 6, 7, 4, 1, 2, 3, 8 };进行升序排序

    2、我们根据锦标赛算法的要求,建立一个满足以上数组要求的完美二叉树数组,并且以上数组中的值是在二叉树的叶节点,并且叶节点必须满足完美二叉树,如果不满足者,给上Integer.MAX_VALUE(20至25行代码,29至37行)

    代码中大家发现使用的并不是int数组,而是Node类的数组,该类中有data和id两个字段。 data是实际的值, id是在数组中的实际索引。 好,大家记住这个,id这块后边会用,并且是算法中的精髓

    3、叶节点我们在上边已经填充上数字了,然后我们需要计算父节点们的值。  父节点i是i*2+1与i*2+2的值比较后,小的值。(代码40至46行)

    4、OK,我们发现,在我们建立竞赛数组成功后,竞赛数组索引0就是最小值啦,哈哈,同时我们知道该最小值在竞赛数组中的索引位置(Node对象中的i就是索引位置啦)。 那么!!重要的来了,我们从这个最小值索引位置与邻节点两两比较,然后向上比最终比到nodes[0]。 然后就又是一个最小值出现啦!!!!重复这个过程,那么最终原始数组就变成降序喽~~!!!!(51至55行代码)

    5、至此,结束,希望大家能看懂。。。。

    PS:锦标赛排序我看了N个博客,我发现最后还是搞不懂,最后看了下边《参考》中的博客中的代码,才最终弄懂。 再次感叹我的资质真的挺差劲的……

    代码

    使用的是java

    package hark.sort.selectionsort;
    
    import java.awt.Adjustable;
    
    /*
     * 锦标赛排序
     */
    public class TournamentTreeSort {
    	public static void main(String[] args) {
    		int[] arrayData = { 5, 9, 6, 7, 4, 1, 2, 3, 8 };
    		TournamentTreeSortMethod(arrayData);
    		for (int integer : arrayData) {
    			System.out.print(integer);
    			System.out.print(" ");
    		}
    	}
    
    	public static void TournamentTreeSortMethod(int[] arrayData) {
    		// 第一步,建立锦标赛使用的是竞赛树节点
    		int leafNum = 1; // 叶子节点的数量,因为是需要完美二叉树,所以叶节点数量需要一直乘以2
    		while (leafNum < arrayData.length) {
    			leafNum *= 2;
    		}
    		int nodeCount = leafNum * 2 - 1; // 这个是竞赛数组的数量
    		Node[] nodes = new Node[nodeCount];
    
    		// 将叶子节点数据进行初始化, 即将arrayData数据初始化至nodes节点中,并且是叶节点,如果不够,
    		// 则初始化为Integer.MAX_VALUE
    		int dataIndex;
    		for (int i = leafNum - 1; i < nodeCount; i++) {
    			dataIndex = i - (leafNum - 1);
    			if (dataIndex < arrayData.length) {
    				nodes[i] = new Node(arrayData[dataIndex], i);
    			} else {
    				nodes[i] = new Node(Integer.MAX_VALUE, i);
    			}
    		}
    
    		// 计算父节点的值。 父节点(n)的值是n*2+1与n*2+2的值的比较
    		for (int i = leafNum - 2; i >= 0; i--) {
    			if (nodes[i * 2 + 1].GetData() < nodes[i * 2 + 2].GetData()) {
    				nodes[i] = nodes[i * 2 + 1];
    			} else {
    				nodes[i] = nodes[i * 2 + 2];
    			}
    		}
    
    		// 这里是真正的排序
    		// 在建竞赛树的时候,nodes中的索引0已经是最小值了,所以将它放到原始数据索引0中,因为它是最小的。
    		// 接着我们知道最小值在竞赛数组中的索引位置,那么我们将该值向上进行两两比较,最终比较至最顶点
    		for (int i = 0; i < arrayData.length; i++) {
    			arrayData[i] = nodes[0].GetData();
    			nodes[nodes[0].GetId()].SetData(Integer.MAX_VALUE);
    			Adjust(nodes, nodes[0].GetId());
    		}
    	}
    
    	/*
    	 * 当去除最小的元素后,我们需要从该元素的索引往上进行数组(是个树哟)的调整
    	 */
    	public static void Adjust(Node[] nodes, int index) {
    		while (index > 0) {
    			// 如果是奇数节点,则临节点是i+1,父节点是(i-1)/2
    			// 如果是偶数节点,则临节点是i-1,父节点是i/2-1
    
    			if (index % 2 == 1) { // 奇数节点
    				if (nodes[index].GetData() < nodes[index + 1].GetData()) {
    					nodes[(index - 1) / 2] = nodes[index];
    				} else {
    					nodes[(index - 1) / 2] = nodes[index + 1];
    				}
    				index = (index - 1) / 2;
    			} else { // 偶数结点
    				if (nodes[index].GetData() < nodes[index - 1].GetData()) {
    					nodes[index / 2 - 1] = nodes[index];
    				} else {
    					nodes[index / 2 - 1] = nodes[index - 1];
    				}
    				index = index / 2 - 1;
    			}
    		}
    	}
    }
    
    class Node {
    	private int data;
    	private int id;
    
    	public int GetData() {
    		return data;
    	}
    
    	public void SetData(int data) {
    		this.data = data;
    	}
    
    	public int GetId() {
    		return id;
    	}
    
    	public Node(int data, int id) {
    		this.data = data;
    		this.id = id;
    	}
    }
    

      

    参考

    http://blog.csdn.net/hopeztm/article/details/7921686

  • 相关阅读:
    php 信号量
    .net 反射初体验
    IEnumerable,IQueryable之前世今生
    [SQL]511+512+534+550+569
    [SQL]183+184+185+196+197
    [SQL]3.26--175+176+177+178+180+181+182
    [剑指offer]10.斐波那契数列+青蛙跳台阶问题
    [剑指offer]14-1.剪绳子
    [剑指offer]62.圆圈中最后剩下的数字
    [剑指offer]52.两个链表的第一个公共节点
  • 原文地址:https://www.cnblogs.com/hark0623/p/4365685.html
Copyright © 2011-2022 走看看