`
cloudtech
  • 浏览: 4605925 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

堆排序详解【java版附流程图】

 
阅读更多

堆排序详解——java版

近期一直再看别人的源码,无意中发现了他里面使用了堆排序算法,由于以前对于堆的排序问题都只是听过,而没有真正的理解过它和实践过它。于是也借本次机会了解了一下堆排序的算法。其实堆的排序是通过二叉树的形式对元素进行排序,它的规律是:ki>=k2i并且ki>=k2i+1或者是ki<=k2i并且ki<=k2i+1,意思就是它的父节点一定大于(小于)它的两个孩子们他们节点,也可以叫大堆排序(小堆排序)下面给出它们的存储结构图:

上面的图是我从百度百科里面截过来的。堆排序是通过数组的形式存储二叉树的信息,那么它就需要计算一个节点的父节点位置,和一个节点的左孩子和右孩子节点的位置,其公式分别为:父=((i+1)/2)-1 左=(2*(i+1))-1 右=2*(i+1)。可以通过以上几个公式计算节点的父节点和孩子节点存储在数组是的位置。所以当向堆中添加元素的时候,将堆的大小添加1,用于存储新添加进来的元素,添加元素的初始存储位置是堆尾(注意此时还未将元素添加到堆中,只是表示在当前堆大小加一的位置将要存放新添加进来的元素)。先找到插入元素存放的位置,也就是将插入的元素和当前堆中最后元素的父节点进行比较,如果比该父节点好,则将父节点移动到移动到插入元素初始存储的位置,而新添加元素此时的存储位置是刚才父节点的存储位置,将继续和父节点的父节点进行比较,重复上面的操作,就是调换新添加的存储位置和当前比较的父节点的位置,直到遇到一个父节点比它好或者是到了堆的顶部则停止寻找。这样会导致一个为题,就是假设新添加的元素不是插在堆的尾部,那么将会导致在插入新元素之后的元素就失去了堆排序的特性,就是父节点比孩子节点大(小),所以此时将还要使用一个heapify(i),方法来进行对插入新元素位置以后的元素进行重新进行堆排序。详细的思路可见代码。以下粘贴处我用java实现的堆排序代码:

public class HeapSort {

	private IntArray vertexts;//该数组是存储元素信息
	private FloatArray weight;//存储元素的权重,注意元素的位置和其对应的权重位置要一一对应
	private IntIntHashMap vertMap;//这个记录元素存储的位置
	private boolean Comparemode;//标记比较方式
	private float maxWeight;//最大的值

	/*public static void main(String[] args) {
		HeapSort sort = new HeapSort(true, Float.MAX_VALUE);
		for (int i = 0; i < 100; i++) {
			sort.addElement(i, (float) Math.random());
		}
		for (int i = 0; i < 100; i++) {
			System.out.print("cost :" + sort.getBestCost() + "-->");
			System.out.println(" Node: " + sort.removeBestElemment());
		}
	}*/
/**
 * 
 * @param Comparemode 该参数设定该推排序是取大的还是小的,当为true时,这取大,否则取小
 * @param maxWeight 设定该堆最差的权重,一般设定为无穷大
 */
	public HeapSort(boolean Comparemode, float maxWeight) {
		this.vertexts = new IntArray();
		this.weight = new FloatArray();
		this.vertMap = new IntIntHashMap();
		this.Comparemode = Comparemode;
		this.maxWeight = maxWeight;
	}

	public boolean compared(float w1, float w2) {
		if (this.Comparemode) {
			if (w1 > w2) {
				return true;
			} else {
				return false;
			}
		} else {
			if (w1 < w2) {
				return true;
			} else {
				return false;
			}

		}
	}

	/**
	 * 方法是想堆中添加元素,并将该元素存储在相应的位置
	 * 
	 * @param v
	 *            元素编号
	 * @param w
	 *            元素值
	 */
	public void addElement(int v, float w) {
		int i = this.vertMap.size();
		int k;
		this.vertexts.add(-1);
		this.weight.add(this.maxWeight);
		while (i > 0 && this.compared(w, this.weight.get(this.parent(i)))) {
			k = this.vertexts.get(this.parent(i));
			this.vertexts.set(i, k);
			this.weight.set(i, this.weight.get(this.parent(i)));
			this.vertMap.add(k, i);
			i = this.parent(i);
		}
		this.vertexts.set(i, v);
		this.weight.set(i, w);
		this.vertMap.add(v, i);

	}

	public float getBestCost() {
		return this.weight.get(0);
	}

	public int getBestVertex() {
		return this.vertexts.get(0);
	}
//移出最好的元素并将该最好的发回给用户
	public int removeBestElemment() {
		if (this.vertexts.size() <= 0) {
			return -1;
		}
		int v = this.vertexts.get(0);
		this.vertMap.remove(v);
		this.vertexts.set(0, this.vertexts.get(this.vertexts.size() - 1));
		this.weight.set(0, this.weight.get(this.weight.size() - 1));
		// 此是因为this.vertexts.get(0)的位置还不确定,所以先付-1表示位置不确定
		this.vertMap.add(this.vertexts.get(0), -1);
		this.vertexts.remove(this.vertexts.size() - 1);
		this.weight.remove(this.weight.size() - 1);
		heapify(0);
		return v;
	}
//移除指定的元素
	public boolean removeElement(int v) {
		if (this.vertexts.size() != 0) {
			int i = this.vertMap.get(v);
			if (i == -1)
				return false;
			this.vertexts.set(i, this.vertexts.get(this.vertexts.size() - 1));
			this.weight.set(i, this.weight.get(this.weight.size() - 1));
			this.vertMap.add(this.vertexts.get(i), i);
			this.vertexts.remove(this.vertexts.size() - 1);
			this.weight.remove(this.weight.size() - 1);
			this.vertMap.remove(v);
			if (i <= this.vertexts.size() - 1) {
				heapify(i);
				Propogate(i);
			}
			return true;
		}
		return false;

	}
//更新你指定的元素信息,当你更新的元素不存在时,则执行添加操作
	public int updateElement(int v, int w) {
		int i = this.vertMap.get(v);
		int k;
		if (i < 0) {
			this.addElement(v, w);
		} else {
			float w1 = this.weight.get(v);
			if (this.compared(w1, w)) {
				return 0;
			}
			while (i > 0 && this.compared(w1, this.weight.get(this.parent(i)))) {
				k = this.vertexts.get(this.parent(i));
				this.vertexts.set(i, k);
				this.weight.set(i, this.weight.get(k));
				this.vertMap.add(k, i);
				i = this.parent(i);
			}
			this.vertexts.set(i, v);
			this.weight.set(i, w);
			this.vertMap.add(v, i);
		}
		return 1;
	}
//调整某位置以后的元素,例如上面删除了指定元素好,将要对元素在堆中的位置进行重新的调整,此时就要调用该函数
	private void heapify(int i) {
		int best = 0;
		int count = this.weight.size() - 1;
		int left = left(i);
		int right = right(i);
		if (left <= count
				&& this.compared(this.weight.get(left), this.weight.get(i))) {
			best = left;
		} else {
			best = i;
		}
		if (right <= count
				&& this.compared(this.weight.get(right), this.weight.get(best))) {
			best = right;
		}
		if (best != i) {
			swap(i, best);
			heapify(best);
		}

	}
//上面调整了后面的元素后,那么该位置上面的父节点也要做相应的调整,此时需调用该函数
	private boolean Propogate(int v) {
		int v_parent = parent(v);
		while (v_parent > 0
				&& this.compared(this.weight.get(v_parent), this.weight.get(v))) {
			swap(v, v_parent);
			v = v_parent;
			v_parent = parent(v_parent);
		}
		return false;
	}
//调换操作,将某一位置的元素和某一位置的元素互换
	private void swap(int i, int j) {
		float wi = this.weight.get(i);
		int vi = this.vertexts.get(i);
		this.weight.set(i, this.weight.get(j));
		this.vertexts.set(i, this.vertexts.get(j));

		this.weight.set(j, wi);
		this.vertexts.set(j, vi);
		this.vertMap.add(this.vertexts.get(i), i);
		this.vertMap.add(this.vertexts.get(j), j);

	}
//得到某个位置节点的父节点位置
	private int parent(int i) {
		return ((i + 1) / 2) - 1;
	}
//得到某个节点左孩子位置
	private int left(int i) {
		return (2 * (i + 1)) - 1;
	}
//获得右孩子位置
	private int right(int i) {
		return 2 * (i + 1);
	}
}


该算法实现上我使用了一个包,该包的功能和我们常使用的utils包的功能一样,至不过,他们里面的Map对象没有put和set方法,它们均只有add,在add的时候会判断集合中是否存在相同的key,如果存在这相当于set方法,如果不存在则相当与put方法,相应的jar包我会上传到我在我的资源里面,有兴趣的可以下载下来,不需积分。在实现上额外的添加了一些方法如

public boolean removeElement(int v) 
public boolean compared(float w1, float w2) 
public int updateElement(int v, int w) 
是为了使得程序能够更好的适应各个场合。

下面粘贴处算法的流程图(只有添加元素的流程图,具体的思想参照我上面的代码):

到此本文结束!谢谢浏览!欢迎评论,指出不足!

分享到:
评论

相关推荐

    堆排序详解升序和降序Java版本

    堆排序,堆排序详解升序和降序Java版本 堆排序的思路主要就是建堆和排序两部分组成。堆排序是基于⼆叉树的,那么我们⾸先得知道⼆叉树得基本特性。我们在堆排序中定义这样⼀种完整⼆叉树,其中每个结点的值都⼤于...

    堆排序7.java 使用java实现的堆排序

    堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆...

    堆排序算法 java

    堆排序算法 java

    堆排序之Java实现

    堆排序算法Java实现

    堆排序12.java 使用java代码实现

    堆排序12.java 使用java代码实现堆排序12.java 使用java代码实现堆排序12.java 使用java代码实现堆排序12.java 使用java代码实现堆排序12.java 使用java代码实现堆排序12.java 使用java代码实现堆排序12.java 使用...

    堆排序算法(流程图、关键代码、复杂度分析)

    堆排序算法其中包含流程图、关键代码、复杂度分析

    堆排序10.java 使用java来实现

    堆排序10.java 使用java来实现堆排序10.java 使用java来实现堆排序10.java 使用java来实现堆排序10.java 使用java来实现堆排序10.java 使用java来实现堆排序10.java 使用java来实现堆排序10.java 使用java来实现堆...

    Java实现堆排序

    Java实现堆排序不是C,Java实现堆排序不是C,Java实现堆排序不是C,Java实现堆排序不是C

    详解Java常用排序算法-堆排序

    详解Java常用排序算法-堆排序

    堆排序算法(java)

    java的堆排序算法实现程序,含测试,可直接运行。java的堆排序算法实现程序,含测试,可直接运行。

    堆排序 java实现

    堆排序算法的java实现,采用大根堆。时间复杂度为O(nlogn).

    堆排序.java 使用Java来实现

    堆排序 堆排序.java 使用Java来实现

    Java集合排序及java集合类详解.pdf

    Java集合排序及java集合类详解.pdf

    数据结构堆排序的java算法实现

    数据结构堆排序的java算法实现,里面用java语言实现了堆排序的算法实现,有输入和输出结果

    [Java算法-排序]-堆排序.java

    该资源提供了Java中实现堆排序的全面指南。文档中涵盖了堆排序的基本概念,包括如何对数组进行排序以及如何在Java中实现堆排序。此外,文档还包括一个逐步指南,介绍了如何在Java中实现堆排序,包括详细的代码示例和...

    排序算法之堆排序【java语言版本】

    排序算法之堆排序【java语言版本】有注释,例子直接拿来演示即可,自行修改参数

    java基础 经典算法之冒泡排序详解

    1.冒泡排序的原理:每次都从第一个元素开始(索引0),向后两两比较,只要后面的比前面的大,就交换(从大到小) 2.通过画图分析,5个数字排4趟,n数字排n-1趟,而外层的for循环代表的是循环的趟数,所以外层循环的结束条件是...

    八大排序-java实现版

    八大排序java实现版本,直接插入排序、折半插入排序、冒泡排序、简单选择排序、希尔插入排序、快速排序 、堆排序、2-路归并排序 、基数排序,并有时间比较,博文...

Global site tag (gtag.js) - Google Analytics