堆和优先级队列

堆的概念:

如果将序列{k1 , k2 , … , kn}对应为一维数组,且序列中元素的下标与数组中下标一致,即数组中下标为 0 的位置不存放数据元素,此时该序列可看成是一颗完全二叉树,则堆的定义说明,在对应的完全二叉树中非终端结点的值均不大于(或不小于)其左右孩子结点的值。


堆排序:

其实感觉画图可以把问题说明,不过我就不画图了。简单的几句话觉得更能说明问题。


第一步,建立堆结构(完全二叉树可以存储到数组中);

第二步,不断的输出堆顶元素,输出后并调整堆的结构,使其重新成为一个堆。


public void heapAdjust(int[] array,int low,int high) {
		int parentNode = array[low];
		for (int j=2*low; j<=high; j=j*2){
			//沿关键之较大的元素向下进行筛选
			//j 指向关键之较大的元素
			if (j<high && (array[j] < array[j+1])) //j < high防止没有右子树的情况
				j++;
			//若 parentNode 比其孩子都大,那么退出循环
			if (parentNode >= array[j]) {
				break;
			} else {	//否则沿着交换的路径继续向下比较
				array[low] = array[j]; 
				low = j; 
			}
		}
		array[low] = parentNode;
	}
		
	public void heapSort() {
		
		int[] array = {0,28,26,17,36,20,42,11,53};
		int n = array.length - 1;
		
		//这里为小技巧,i=n/2为一个完全二叉树的最后一个叶子节点的父节点,然后沿逆时针方向倒叙
		//遍历每一个父节点
		for (int i=n/2; i>=1; i--) {//4 3 2 1
			heapAdjust(array,i,n);
		}
		for (int i=n; i>1; i--) {
			//不断输出堆顶元素并调整 array[1..i-1]为新堆
			int temp = array[1];
			//交换堆顶与堆底元素
			array[1] = array[i];
			array[i] = temp;
			heapAdjust(array,1,i-1);
		}
		
		for(int i = 0;i<=n;i++)
			System.out.println(array[i]);
	}
</pre><pre name="code" class="java">
2,优先级队列,其实堆就是一种特殊的优先级队列。每次取数据的时间复杂度为1(把优先级最高的元素取出),插入元素的过程为把一个元素插入到有序的队列之中(按优先级排序)时间复杂度为log2N。
下面给出了一种插入算法和一种二分查找算法,只要把二分查找变为二分查找后插入就可以了。
</pre><pre name="code" class="java"><pre name="code" class="java">public static void main(String args[]) {
		int[] array = {1,2,3,4,5,6,7};
		System.out.println(erfinsert(array,1,0,6));
	}

	public void insert(int[] array, int insertData, int reallength) {
		int i, j;
		if (insertData < array[0]) {
			for (i = reallength; i > 0; i--) {
				array[i] = array[i - 1];
			}
			array[i] = insertData;
		} else if (insertData > array[reallength - 1]) {
			array[reallength] = insertData;
		} else {
			for (i = 0; i < reallength; i++) {
				if (insertData > array[i] && insertData <= array[i + 1]) {
					for (j = reallength; j > i; j--) {
						array[j] = array[j - 1];
					}
					array[j] = insertData;
					break;
				}
			}
		}
	}
	
	public static int erfinsert(int[] arr, int data, int low,int high) {
		int mid = 0;
		while(low <= high) {
			mid = (low + high)/2;
			if(arr[mid] == data)
				return mid;
			else if(arr[mid] > data) {
				high = mid -1;
				continue;
			} else if(arr[mid] < data) {
				low = mid +1;
				continue;
			}
		}
		return -1;
		
	}

下面补充一个折半插入排序吧:


public void binInsertSort(int[] array, int low, int high) {
		for (int i = low + 1; i <= high; i++) {
			int temp = array[i];
			// 保存待插入元素
			int hi = i - 1;
			int lo = low;
			// 设置初始区间
			while (lo <= hi) {
				// 折半确定插入位置
				int mid = (lo + hi) / 2;
				if (temp < array[mid])
					hi = mid - 1;
				else
					lo = mid + 1;
			}
			for (int j = i - 1; j > hi; j--)
				array[j + 1] = array[j]; // 移动元素
			array[hi + 1] = temp;
			// 插入元素
		}// for
	}


 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值