算法设计与分析java_关于算法设计与分析基之堆的示例

以数组来存放堆数据package cn.xf.algorithm.ch06ChangeRule;

import java.util.ArrayList;

import java.util.List;

import org.junit.Test;

/**

*

* 功能:堆的构造

* 1、堆可以定义为一颗二叉树,树的节点包含键,并且满足一下条件

* 1) 树的形状要求:这棵二叉树是基本完备的(完全二叉树),树的每一层都是满的,除了最后一层最右边的元素可能缺位

* 2) 父母优势,堆特性,每一个节点的键都要大于或者等于他子女的键(对于任何叶子我们认为这都是自动满足的)

*

* 对于堆:

* 只存在一颗n个节点的完全二叉树他的高度:取下界的 log2的n的对数

* 堆的根总是包含了堆的最大元素

* 堆的一个节点以及该节点的子孙也是一个堆

* 可以用数组的来实现堆,方法是从上到下,从左到右的方式来记录堆的元素。

* @author xiaofeng

* @date 2017年7月9日

* @fileName Heap.java

*

*/

public class Heap {

/**

* 堆的数据存放结构

*/

private List heap;

/**

* 自下而上构建一个堆

*/

private List createHeadDownToUp(List heap) {

if(heap == null || heap.size() <= 0)

return heap;

//数据个数

int nums = heap.size();

//吧数组整体后移一位,方便数据的计算,因为从0开始,那么2*0还是0,没有体现出2*n就是n的左孩子的基本设定

heap.add(0, 0d);

//构建一个堆,从数组的中间位置开始,因为中间位子mid的两倍正好差不多是这个树的末尾,而在这个2*mid的附近就是mid这个节点的孩子节点

for(int i = nums / 2 + 1; i > 0; --i) {

//获取基准节点的地址

int baseIndex = i;

//获取这个节点的值

double vBaseValue = heap.get(baseIndex);

boolean isHeap = false; //这个用来判断当前遍历的这三个数字是否满足堆的概念

//进行堆变换,交换树的节点和孩子节点数值,使当前树满足堆的概念

//2 * baseIndex <= nums 这个用来判断这颗树的子树也满足堆的定义

while(!isHeap && 2 * baseIndex <= nums) {

//获取当前遍历到的数据的左孩子节点的位置

int maxChildIndex = 2 * baseIndex;

//从两个孩子节点中获取大的那个位置

if(maxChildIndex < nums) {

//如果左孩子的位置比总长还小,由于完全二叉树的属性,那么必定存在右孩子节点

//判断那个孩子节点的数据比较大,使max为大的那个

if(heap.get(maxChildIndex) < heap.get(maxChildIndex + 1)) {

//如果右孩子比较大

maxChildIndex += 1;

}

}

//再判断,当前 节点的值是不是比孩子节点的值要大,如果是那么就当前子树是满足堆的属性

//maxChildIndex == nums 那还是瞒住条件,可以进行左子树的比较

if(maxChildIndex > nums || vBaseValue >= heap.get(maxChildIndex)) {

isHeap = true;

} else {

//如果不满住,那么交换,吧大的数据交换到节点上,吧节点的数据换到孩子节点上

heap.set(baseIndex, heap.get(maxChildIndex));

baseIndex = maxChildIndex;

heap.set(baseIndex, vBaseValue);

}

}

}

//去除第一个0,然后返回

heap.remove(0);

return heap;

}

private void shifHeadDownToUp(int i) {

if (heap == null || heap.size() <= 0)

return;

// 数据个数

int nums = heap.size();

// 吧数组整体后移一位,方便数据的计算,因为从0开始,那么2*0还是0,没有体现出2*n就是n的左孩子的基本设定

heap.add(0, 0d);

boolean isHeap = false;

int baseIndex = i;

double vBaseValue = heap.get(i);

while (!isHeap && 2 * baseIndex <= nums) {

// 获取当前遍历到的数据的左孩子节点的位置

int maxChildIndex = 2 * baseIndex;

// 从两个孩子节点中获取大的那个位置

if (maxChildIndex < nums) {

// 如果左孩子的位置比总长还小,由于完全二叉树的属性,那么必定存在右孩子节点

// 判断那个孩子节点的数据比较大,使max为大的那个

if (heap.get(maxChildIndex) < heap.get(maxChildIndex + 1)) {

// 如果右孩子比较大

maxChildIndex += 1;

}

}

// 再判断,当前 节点的值是不是比孩子节点的值要大,如果是那么就当前子树是满足堆的属性

// maxChildIndex == nums 那还是瞒住条件,可以进行左子树的比较

if (maxChildIndex > nums || vBaseValue >= heap.get(maxChildIndex)) {

isHeap = true;

} else {

// 如果不满住,那么交换,吧大的数据交换到节点上,吧节点的数据换到孩子节点上

heap.set(baseIndex, heap.get(maxChildIndex));

baseIndex = maxChildIndex;

heap.set(baseIndex, vBaseValue);

}

}

// 去除第一个0,然后返回

heap.remove(0);

}

//创建堆

public Heap() {

heap = new ArrayList();

createHeadDownToUp(heap);

}

public Heap(List data) {

if(data == null || data.size() <= 0) {

data = new ArrayList();

}

heap = data;

createHeadDownToUp(heap);

}

@Override

public String toString() {

return heap.toString();

}

public void add(Double value) {

if(value == null)

return;

heap.add(value);

// int insertInedx = heap.size();

//自底向上构建堆

for(int i = heap.size() / 2; i >= 0; --i) {

shifHeadDownToUp(i + 1);

}

}

/**

* 删除一个元素,获取这个元素的索引位置来删除

* 1、根的键《和》堆的最后一个键K做交换

* 2、堆的规模减一

* 3、严格按照自底向上的够着算法的做法,吧K 向下筛选,堆数据进行堆化

* @param index

*/

public void delete(int index) {

//这个是自底向上进行堆化数据

//吧最后一个数据填入到要删除的数据中

Double lastValue = heap.get(heap.size() - 1);

//删除最后一个元素,吧最后一个元素用来取代这个需要删除的元素

heap.set(index, lastValue);

heap.remove(heap.size() - 1);

//自底向上开始堆化

for(int i = index; i >= 0; --i)

shifHeadDownToUp(i + 1);

}

}

利用Java编写的几种经典问题算法: 1.设a[0:n-1]是一个有n个元素的数组,k(0<=k<=n-1)是一个非负整数。 试设计一个算法将子数组a[0:k]与a[k+1,n-1]换位。要求算法在最坏情况下耗时O(n),且只用到O(1)的辅助空间。 2.在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分,并分析算法的计算复杂性。 3.设磁盘上有n个文件f1,f2,…,fn,每个文件占用磁盘上的1个磁道。这n个文件的检索概率分别是p1,p2,…,pn,且 =1。磁头从当前磁道移到被检信息磁道所需的时间可用这2个磁道之间的径向距离来度量。如果文件fi存放在第i道上,1≦i≦n,则检索这n个文件的期望时间是对于所有的i<j,time+=pi*pj*d(i,j) 。其中d(i,j)是第i道与第j道之间的径向距离|i-j|。磁盘文件的最优存储问题要求确定这n个文件在磁盘上的存储位置,使期望检索时间达到最小。试设计一个解决此问题的算法,并分析算法的正确性与计算复杂度。 4.最小重量机器设计问题。设某一机器由n个部件组成,每一种部件可以从m个不同的供应商处购得。设wij是从供应商j处购得的部件i的重量,cij是相应的价格。试设计一个算法,给出总价格不超过c的最小重量机器设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值