【算法设计与分析基础】23、堆排序-2

package cn.xf.algorithm.ch09Greedy.util;

import java.util.ArrayList;
import java.util.List;

/**
 * 堆构造以及排序
 *
 * .功能:堆的构造
 *  1、堆可以定义为一颗二叉树,树的节点包含键,并且满足一下条件
 *  1) 树的形状要求:这棵二叉树是基本完备的(完全二叉树),树的每一层都是满的,除了最后一层最右边的元素可能缺位
 *  2) 父母优势,堆特性,每一个节点的键都要大于或者等于他子女的键(对于任何叶子我们认为这都是自动满足的)
 *
 * 对于堆:
 *   只存在一颗n个节点的完全二叉树他的高度:取下界的 log2的n的对数
 *  堆的根总是包含了堆的最大元素
 *  堆的一个节点以及该节点的子孙也是一个堆
 *  可以用数组的来实现堆,方法是从上到下,从左到右的方式来记录堆的元素。
 *
 * @author xiaof
 * @version Revision 1.0.0
 * @see:
 * @创建日期:2017年8月25日
 * @功能说明:
 *
 */
public class Heap {
    private List<Integer> heap;

    //构造函数
    public Heap() {
    	//创建堆
        heap = new ArrayList<Integer>();
    }

    public Heap(List<Integer> heap) {
    	//创建堆
    	this.heap = heap;
        createHeadDownToUp(this.heap);
    }

    /**
     * 从小到大的堆
     * @param heap
     * @return
     */
    private void createHeadDownToUp(List<Integer> heap){
        //对数组进行堆排序
    	if(heap == null || heap.size() <= 0)
    		return;
    	int len = heap.size();
    	//从树的中间开始循环
    	for(int i = len / 2; i > 0; --i) {
    		//首先预存当前进行操作的节点‘
    		//索引和值
    		int selectIndex = i - 1;
    		int selectValue = heap.get(selectIndex);
    		boolean isHeap = false; //用来判断当前节点下是否已经没有其他节点比这个节点小了,作为是否成堆的标识
    		while(!isHeap && 2 * (selectIndex + 1) <= len) {
    			//当前节点的最大的孩子节点的位置,开始默认是第一个孩子节点的位置
        		int childIndex = 2 * i - 1;
        		//判断是否存在两个孩子节点,如果存在,那么就选出最大的那个
        		if(2 * i < len) {
        			//获取比较小的那个节点作为备选替换节点
        			childIndex = heap.get(childIndex) < heap.get(childIndex + 1) ? childIndex : childIndex + 1;
        		}
        		//判断当前节点是不是比下面最小的那个节点还要小
        		if(selectValue <= heap.get(childIndex)) {
        			//如果比下面最大的还大,那就表明这个节点为根的子树已经是一颗树了
        			isHeap = true;
        		} else {
        			//如果节点不是小的,那么更换掉
        			heap.set(selectIndex, heap.get(childIndex));
        			//并交换当前遍历交换的节点
        			selectIndex = childIndex;
        			//这个节点和子节点全部遍历结束之后,交换出最初用来交换的选中节点
            		heap.set(selectIndex, selectValue);
        		}
    		}
    	}
    }

    /**
     * 对堆的节点的单次变换
     * @param i 第几个节点
     */
	private void shifHeadDownToUp(int i) {
		if(heap == null || heap.size() <= 0)
			return;
		int len = this.heap.size();
		//索引i需要存在于这个节点中
		if(i >= len)
			return;
		// 首先预存当前进行操作的节点‘
		// 索引和值
		int selectIndex = i - 1;
		int selectValue = heap.get(selectIndex);
		boolean isHeap = false; // 用来判断当前节点下是否已经没有其他节点比这个节点小了,作为是否成堆的标识
		while (!isHeap && 2 * (selectIndex + 1) <= len) {
			// 当前节点的最大的孩子节点的位置,开始默认是第一个孩子节点的位置
			int childIndex = 2 * (selectIndex + 1) - 1;
			// 判断是否存在两个孩子节点,如果存在,那么就选出最大的那个
			if (2 * (selectIndex + 1) < len) {
				// 获取比较小的那个节点作为备选替换节点
				childIndex = heap.get(childIndex) < heap.get(childIndex + 1) ? childIndex : childIndex + 1;
			}
			// 判断当前节点是不是比下面最小的那个节点还要小
			if (selectValue <= heap.get(childIndex)) {
				// 如果比下面最大的还大,那就表明这个节点为根的子树已经是一颗树了
				isHeap = true;
			} else {
				// 如果节点不是小的,那么更换掉
				heap.set(selectIndex, heap.get(childIndex));
				// 并交换当前遍历交换的节点
				selectIndex = childIndex;
				// 这个节点和子节点全部遍历结束之后,交换出最初用来交换的选中节点
				heap.set(selectIndex, selectValue);
			}
		}

	}

	//向堆添加元素
	public void add(int element) {
//		int oldLen = heap.size();
		heap.add(element);
		//然后从加入的位置的父节点开始,从下向上所有父节点,全部变换一次
		for(int i = heap.size() / 2; i > 0; i = i / 2) {
			this.shifHeadDownToUp(i);
		}
	}

	/**
	 * 移除堆中一个指定元素
	 * @param index
	 * @return
	 */
//	public int remove(int index) {
//		int result = heap.get(index - 1);
//		//思路是吧剩下的最后一个元素作为参照元素,填充进去
//		int lastValue = heap.get(heap.size() - 1);
//		heap.set(index - 1, lastValue);
//		heap.remove(heap.size() - 1);
//		//然后从下向上,吧这个节点对应的位置的数据进行递归
//		for(int i = index; i > 0; i = i / 2) {
//			this.shifHeadDownToUp(i);
//		}
//		return result;
//	}

	public int remove(Integer object) {
		int index = heap.indexOf(object);
		//思路是吧剩下的最后一个元素作为参照元素,填充进去
		int lastValue = heap.get(heap.size() - 1);
		heap.set(index, lastValue);
		heap.remove(heap.size() - 1);
		//然后从下向上,吧这个节点对应的位置的数据进行递归
		for(int i = index + 1; i > 0; i = i / 2) {
			this.shifHeadDownToUp(i);
		}
		return index;
	}

	/**
	 * 默认删除根节点
	 * @return
	 */
	public int remove() {
		int result = heap.get(0);
		//思路是吧剩下的最后一个元素作为参照元素,填充进去
		int lastValue = heap.get(heap.size() - 1);
		heap.set(0, lastValue);
		heap.remove(heap.size() - 1);
		//然后从下向上,吧这个节点对应的位置的数据进行递归
		for(int i = 1; i > 0; i = i / 2) {
			this.shifHeadDownToUp(i);
		}
		return result;
	}

    @Override
	public String toString() {
	    return heap.toString();
	}
}

  

时间: 2024-12-23 10:52:20

【算法设计与分析基础】23、堆排序-2的相关文章

算法设计与分析基础(第3版)读书笔记(及几处翻译上的错误~~)

算法设计与分析基础(第3版) p16 in-place翻译为'在位'?'就地'更合适点 p38 amortized应翻译为'均摊','摊销'这个词简直莫名其妙(可能因为翻译是做算法交易导致的?) p64 迭代优于递归(迭代始终是增量式的,而递归就没办法增量了,除非能够dump整个运行时栈) p73 通过算法可视化得到一个更好的非递归算法(人的图像认知直觉思维?) p79 验证一个拓扑是环.星.还是团?(这个地方有点意思,因为我想到了动态的Verify) p87 凸包问题:从数据结构上讲,Set<

【算法设计与分析基础】大整数乘法

#include<iostream> #include<string> #include<time.h> #include<stdlib.h> #include<sstream> using namespace std; class BigDecimal{ private: int max(int a,int b){//获取两数中的最大值 return a^((a^b) & -(a<b)); } public: string n;

【算法设计与分析基础】关灯游戏

① R.java  用于存储一些全局变量 package lightoff; public class R { /* public static int lightCondition[][] = { {1,0,0,1,1}, {1,0,0,1,1}, {1,0,0,1,1}, {1,0,0,1,1}, }; */ public static int lightCondition[][] = { {1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1}, }; //灯面

【算法设计与分析基础】19、字符串匹配算法

package cn.xf.algorithm.ch07inputEnhancement; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; /** * * 功能:字符串匹配算法,(还有一种叫KMP算法的,也是很经典的算法,就是比较复杂) * * 第一步:对于给定的长度为m的模式和在模式文本中用到的字母表,按照上面的描述构造移动表 * 第二步:将模式与文本的开

【算法设计与分析基础】16、高斯消元法

package cn.xf.algorithm.ch06ChangeRule; import java.util.ArrayList; import java.util.List; import org.junit.Test; import cn.xf.util.GenericPair; /** * * 功能:高斯消元法,也就是多元数据矩阵,依次吧每列的其他行数据消去为0,然后求出一个元的解,然后就可以根据这个数据来递推出其他元的解 * @author xiaofeng * @date 2017

【算法设计与分析基础】20、动态规划-硬币搜集问题

题目: 在n*m格木板中放有一些硬币,每格的硬币数目最多为一个.在木板左上方的一个机器人需要搜集尽可能多的硬币并把他们带到右下方的单元格,每一步,机器人可以从当前的位置向右移动一格 或者向下移动一格,当机器人遇到一个有硬币的单元格的时,就会将这枚硬币搜集起来 解题: 硬币收集的时候,我们 从结果状态开始看,当搜集当前硬币的时候,只有两种方式,从上往下搜集,或者从左向右搜集 也就是当前f[i,j] = max{f[i, j - 1], f[i - 1, j]},初始化第一行和第一列,从第二行和列开

【算法设计与分析基础】17、堆

以数组来存放堆数据 package cn.xf.algorithm.ch06ChangeRule; import java.util.ArrayList; import java.util.List; import org.junit.Test; /** * * 功能:堆的构造 * 1.堆可以定义为一颗二叉树,树的节点包含键,并且满足一下条件 * 1) 树的形状要求:这棵二叉树是基本完备的(完全二叉树),树的每一层都是满的,除了最后一层最右边的元素可能缺位 * 2) 父母优势,堆特性,每一个节点

【算法设计与分析基础】18、霍纳法则

产生随机数 package cn.xf.algorithm.ch02; import java.util.ArrayList; import java.util.List; /** * 生产随机数 * @author xiaof * */ public class Random { /** * 生产一个随机数的数列 * @param n 生成n个数列 * @param m 数据在0和m-1之间 * @param seed 随机初始种子 * @param a 参数 * @param b 参数 *

【算法设计与分析基础】12、插入排序

package cn.xf.algorithm.ch04; import org.junit.Test; /** * * * . * @author xiaof * @version Revision 1.0.0 * @see: * @创建日期:2017年5月23日 * @功能说明:插入排序 * */ public class InsertSort { /** * 插入排序,核心思想是,遍历这个数据,然后把所有的所有的数据从前往后往这个空位拉开一个身位, * 直到找到比这个数小的位置后面,往这个