堆排序(JAVA)实现和杨氏矩阵查找
2013-10-21 22:07
316 查看
最近看到一道创新工程2014年校招的题目:输入一个整形无序数组,用堆排序的方法使其有序。楼主网上搜罗各种资料,然后自己花了点时间认真的研究一番堆排序。以下为参考的网址:http://student.zjzk.cn/course_ware/data_structure/web/paixu/paixu8.4.2.2.htm(数据结构网站)http://www.cnblogs.com/zabery/archive/2011/07/26/2117103.html堆排序与分析。
一、 堆排序定义
n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):
(1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤
)
若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
【例】关键字序列(10,15,56,25,30,70)和(70,56,30,25,15,10)分别满足堆性质(1)和(2),故它们均是堆,其对应的完全二叉树分别如小根堆示例和大根堆示例所示。
二、大根堆和小根堆
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆。
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆。
注意:
①堆中任一子树亦是堆。
②以上讨论的堆实际上是二叉堆(Binary Heap),类似地可定义k叉堆。
三、堆排序特点
堆排序(HeapSort)是一树形选择排序。
堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系【参见二叉树的顺序存储结构】,在当前无序区中选择关键字最大(或最小)的记录。
四、堆排序与直接插入排序的区别
直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。
堆排序可通过树形结构保存部分比较结果,可减少比较次数。
五、性能分析:
调堆:上面已经分析了,调堆的运行时间为O(h)。
建堆:每一层最多的节点个数为n1 = ceil(n/(2^(h+1))),
因此,建堆的运行时间是O(n)。
循环调堆(代码67-74),因为需要调堆的是堆顶元素,所以运行时间是O(h) = O(floor(logn))。所以循环调堆的运行时间为O(nlogn)。
总运行时间T(n) = O(nlogn) + O(n) = O(nlogn)。对于堆排序的最好情况与最坏情况的运行时间,因为最坏与最好的输入都只是影响建堆的运行时间O(1)或者O(n),而在总体时间中占重要比例的是循环调堆的过程,即O(nlogn) + O(1) =O(nlogn) + O(n) = O(nlogn)。因此最好或者最坏情况下,堆排序的运行时间都是O(nlogn)。而且堆排序还是原地算法
六、程序代码:
杨氏矩阵:在一个m行n列二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
定位法思路:
定位法,时间复杂度O(m+n)。首先直接定位到最右上角的元素,再配以二分查找,比要找的数(6)大就往左走,比要找数(6)的小就往下走,直到找到要找的数字(6)为止,如下图所示:
Java代码实现:
一、 堆排序定义
n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):
(1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤
)
若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
【例】关键字序列(10,15,56,25,30,70)和(70,56,30,25,15,10)分别满足堆性质(1)和(2),故它们均是堆,其对应的完全二叉树分别如小根堆示例和大根堆示例所示。
二、大根堆和小根堆
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆。
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆。
注意:
①堆中任一子树亦是堆。
②以上讨论的堆实际上是二叉堆(Binary Heap),类似地可定义k叉堆。
三、堆排序特点
堆排序(HeapSort)是一树形选择排序。
堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系【参见二叉树的顺序存储结构】,在当前无序区中选择关键字最大(或最小)的记录。
四、堆排序与直接插入排序的区别
直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。
堆排序可通过树形结构保存部分比较结果,可减少比较次数。
五、性能分析:
调堆:上面已经分析了,调堆的运行时间为O(h)。
建堆:每一层最多的节点个数为n1 = ceil(n/(2^(h+1))),
因此,建堆的运行时间是O(n)。
循环调堆(代码67-74),因为需要调堆的是堆顶元素,所以运行时间是O(h) = O(floor(logn))。所以循环调堆的运行时间为O(nlogn)。
总运行时间T(n) = O(nlogn) + O(n) = O(nlogn)。对于堆排序的最好情况与最坏情况的运行时间,因为最坏与最好的输入都只是影响建堆的运行时间O(1)或者O(n),而在总体时间中占重要比例的是循环调堆的过程,即O(nlogn) + O(1) =O(nlogn) + O(n) = O(nlogn)。因此最好或者最坏情况下,堆排序的运行时间都是O(nlogn)。而且堆排序还是原地算法
六、程序代码:
package cn.edu.test1; import java.util.Random; /** * 堆排序 * 堆排序定义:n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质): (1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤ ) */ public class HeapSort { public static int N = 10000000; //数组的长度 /** * * @param R 待排序数组 */ private void buildHeap(int[] R){ int length = R.length; int begin = length/2 -1; //The last leaf node for(int i=begin;i>=0;i--) { heapify(R,length,i); //adjust heap } } /** * 调整无序为一个新的堆 * @param R 待调整数组R * @param start 调整数组的无序 * @param end 调整数组的无序区结束位置 */ private void heapify(int[] R,int hlen,int i){ int left =2*i+1; //节点i的左孩子节点 int right =2*i+2; //节点i的右孩子节点 int largest = i; int temp; while(left<hlen || right<hlen){ if(left<hlen && R[largest]<R[left]){ largest = left; } if(right<hlen && R[largest]<R[right]){ largest = right; } if(i !=largest){ //如果最大值不是父节点,则交换父节点和拥有最大值的子节点交换 temp=R[largest]; R[largest]=R[i]; R[i] =temp; i = largest; //新的父节点,以备迭代调堆 left = 2*i+1; //新的子节点 right =2*i+2; } else{ break; } } } /** * 打印输出数组数据 * @param R */ private void printArray(int[] R){ int length = R.length; for(int i=0;i<length;i++){ System.out.print(R[i]+","); if((i+1)%20==0) System.out.println(); } System.out.println(); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub HeapSort obj = new HeapSort(); //堆排序 Random ran = new Random(); int[] R = new int ; //声明n+1个数组,R[0]作为交换位 for(int i=0;i<N;i++) { R[i]=ran.nextInt(N); // } int hlen = R.length; int temp; //obj.printArray(R); //初始化后的输出 obj.buildHeap(R); //init heap // obj.printArray(R); //构建堆后的输出 while(hlen>1){ temp = R[hlen-1]; R[hlen-1] = R[0]; R[0] =temp; hlen--; //堆的大小减一 obj.heapify(R, hlen, 0); //修改后重新调整堆 } // System.out.println(hlen); obj.printArray(R); // System.out.println("堆排序流程"); } }
杨氏矩阵:在一个m行n列二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
定位法思路:
定位法,时间复杂度O(m+n)。首先直接定位到最右上角的元素,再配以二分查找,比要找的数(6)大就往左走,比要找数(6)的小就往下走,直到找到要找的数字(6)为止,如下图所示:
Java代码实现:
package cn.edu.test1; /** * 在一个m行n列二维数组中,每一行都按照从左到右递增的顺序排序, * 每一列都按照从上到下递增的顺序排序。请完成一个函数, * 输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 * @author Tomas * */ public class Young { /** * * @param m 矩阵行 * @param n 矩阵列 * @return */ private int[][] getMatrix(int m,int n){ if(m<0 ||n<0) return null; int k = 1; int[][] matrix = new int[m] ; //initial matrix for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ matrix[i][j]=k++; } } return matrix; } /** * 杨氏矩阵,定位法解决问题 */ public String young(int[][] matrix,int value){ int row = matrix.length; int column = matrix[0].length; int i =0,j=column; while(i<row && j>0){ if(matrix[i][j-1]>value){ j--; } else if(matrix[i][j-1]<value){ i++; } else{ return "Find it in "+(i+1)+" row and "+j+" column"; } } return "Not Find it"; } public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("Young Matrix"); Young obj = new Young(); String result = obj.young(obj.getMatrix(4,5),17); System.out.println(result); } }
相关文章推荐
- 杨氏矩阵查找的Java实现
- 杨氏矩阵查找元素位置Java实现
- 杨氏矩阵查找元素位置Java实现
- 【杨氏矩阵查找元素位置Java实现】
- 用堆排序实现查找最小的K个元素 java
- 数据结构与算法分析笔记与总结(java实现)--排序11:有序矩阵查找练习题
- 经典面试题:求数组的最大子序列和;实现函数 :判断一个自负喜欢是否是另一个字符串旋转所得;杨氏矩阵中查找一个数。
- 杨氏矩阵查找实现
- java实现查找一个字符串在另一个字符串出现的次数
- 数据结构:JAVA_二叉数查找树基本实现(中)
- 华为OJ 查找组成一个偶数最接近的两个素数 Java实现
- android用java和c实现查找sd卡挂载路径(sd卡路径)的方法
- java语言实现常用算法(排序和查找)
- java实现的堆排序(java)
- 有序表查询之一:java实现整型数组二分查找
- 数据算法之二叉树查找(BinaryTreeL Search)的Java实现
- 堆排序及其Java实现
- 顺时针打印矩阵 (JAVA实现)
- 矩阵最小路径和(java实现)
- Java实现快速排序、归并排序、堆排序和希尔排序