未提示来源的算法步骤皆来自于http://kb.cnblogs.com/page/210687/
来源:百度百科之快速排序算法
一.快速排序:
快速排序(Quicksort)是对冒泡排序的一种改进。
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
算法介绍:
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
排序演示:可参见百度百科中的排序演示。很容易看懂和理解。
快速排序算法步骤:
1从数列中挑出一个元素,称为“基准”(pivot),
2重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
代码来源:百度百科快速排序算法之Java版本
/**
* 快速排序法,最基本版,效率很低
* 成功通过测试
@param array
* @param low
* @param high
*/
public static void quickSort1(int[] array,int low,int high)
{
int l=low;
int h=high;
int pivot=array[low];
int n=array.length-1;
while(l<h)
{
while(l<h && array[h]>=pivot)
{
h--;
}
if(l<h)
{
int temp=array[h];
array[h]=array[l];
array[l]=temp;
l++;
}
while(l<h&& array[l]<=pivot)
{
l++;
}
if(l<h)
{
int temp=array[h];
array[h]=array[l];
array[l]=temp;
h--;
}
}
print(array);
System.out.print("low="+(low+1)+",h="+(high+1)+",pivot="+pivot+"\n");
if(l>low)quickSort1(array,low,l-1);
if(h<high)quickSort1(array,l+1,high);
}
///*///方式二//*/
//更高效---- 因对泛型使用比较生疏,所以部分内容没能修改完善。
public <T extends Comparable<? super T>>T[]quickSort2(T[] targetArr,int start,int end)
{
int i=start+1,j=end;
T key=targetArr[start];
SortUtil<T> sUtil=new SortUtil<T>();
if(start>=end)return(targetArr);
/*从i++和j--两个方向搜索不满足条件的值并交换
*
*条件为:i++方向小于key,j--方向大于key*/
while(true)
{
while(targetArr[j].compareTo(key)>0)j--;
while(targetArr[i].compareTo(key)<0&&i<j)i++;
if(i>=j)break;
sUtil.swap(targetArr,i,j);
if(targetArr[i]==key)
{
j--;
}
else
{
i++;
}
}
//关键数据放到‘中间’
sUtil.swap(targetArr,start,j);
if(start<i-1)
{
this.quickSort2(targetArr,start,i-1);
}
if(j+1<end)
{
this.quickSort2(targetArr,j+1,end);
}
return targetArr;
}
/*///方式三:减少交换次数,提高效率*/
//因对泛型掌握不够,测试未能有效
private <T extends Comparable<? super T>> void quickSort3(T[]targetArr,int start,int end)
{
int i=start,j=end;
T key=targetArr[start];
while(i<j)
{
/*按j--方向遍历目标数组,直到比key小的值为止*/
while(j>i&&targetArr[j].compareTo(key)>=0)
{
j--;
}
if(i<j)
{
/*targetArr[i]已经保存在key中,可将后面的数填入*/
targetArr[i]=targetArr[j];
i++;
}
/*按i++方向遍历目标数组,直到比key大的值为止*/
while(i<j&&targetArr[i].compareTo(key)<=0)
/*此处一定要小于等于零,假设数组之内有一亿个1,0交替出现的话,而key的值又恰巧是1的话,那么这个小于等于的作用就会使下面的if语句少执行一亿次。*/
{
i++;
}
if(i<j)
{
/*targetArr[j]已保存在targetArr[i]中,可将前面的值填入*/
targetArr[j]=targetArr[i];
j--;
}
}
/*此时i==j*/
targetArr[i]=key;
/*递归调用,把key前面的完成排序*/
this.quickSort3(targetArr,start,i-1);
/*递归调用,把key后面的完成排序*/
this.quickSort3(targetArr,j+1,end);
}
二.堆排序
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。(摘自百度百科)
算法步骤:
1.创建一个堆H[0..n-1]
2.把堆首(最大值)和堆尾互换
3.把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4.重复步骤2,直到堆的尺寸为1
代码来源:百科-未测试
public class HeapSort{
private static int[] sort=new int[]{1,0,10,20,3,5,6,4,9,8,12,
17,34,11};
public static void main(String[] args){
buildMaxHeapify(sort);
heapSort(sort);
print(sort);
}
private static void buildMaxHeapify(int[] data){
//没有子节点的才需要创建最大堆,从最后一个的父节点开始
int startIndex=getParentIndex(data.length-1);
//从尾端开始创建最大堆,每次都是正确的堆
for(int i=startIndex;i>=0;i--){
maxHeapify(data,data.length,i);
}
}
/**
*创建最大堆
*
*@paramdata
*@paramheapSize需要创建最大堆的大小,一般在sort的时候用到,因为最多值放在末尾,末尾就不再归入最大堆了
*@paramindex当前需要创建最大堆的位置
*/
private static void maxHeapify(int[] data,int heapSize,int index){
//当前点与左右子节点比较
int left=getChildLeftIndex(index);
int right=getChildRightIndex(index);
int largest=index;
if(left<heapSize&&data[index]<data[left]){
largest=left;
}
if(right<heapSize&&data[largest]<data[right]){
largest=right;
}
//得到最大值后可能需要交换,如果交换了,其子节点可能就不是最大堆了,需要重新调整
if(largest!=index){
int temp=data[index];
data[index]=data[largest];
data[largest]=temp;
maxHeapify(data,heapSize,largest);
}
}
/**
*排序,最大值放在末尾,data虽然是最大堆,在排序后就成了递增的
*
*@paramdata
*/
private static void heapSort(int[] data){
//末尾与头交换,交换后调整最大堆
for(int i=data.length-1;i>0;i--){
int temp=data[0];
data[0]=data[i];
data[i]=temp;
maxHeapify(data,i,0);
}
}
/**
*父节点位置
*
*@paramcurrent
*@return
*/
private static int getParentIndex(int current){
return(current-1)>>1;
}
/**
*左子节点position注意括号,加法优先级更高
*
*@paramcurrent
*@return
*/
private static int getChildLeftIndex(int current){
return(current<<1)+1;
}
/**
*右子节点position
*
*@paramcurrent
*@return
*/
private static int getChildRightIndex(int current){
return(current<<1)+2;
}
private static void print(int[] data){
int pre=-2;
for(int i=0;i<data.length;i++){
if(pre<(int)getLog(i+1)){
pre=(int)getLog(i+1);
System.out.println();
}
System.out.print(data[i]+"|");
}
}
/**
*以2为底的对数
*
*@paramparam
*@return
*/
private static double getLog(double param){
return Math.log(param)/Math.log(2);
}
}
代码:来源http://blog.youkuaiyun.com/yunshuixiliu/article/details/21015161
未测试
package sort;
import java.util.Random;
public class HeapSort extends AbstractSort {
public static void sort(Comparable[] a){
buildHeap(a); // 建立堆
for(int i= a.length - 1 ; i >=1 ; i--){
exch(a,0,i);
adjust(a,0,i); //注意i 的值,开始的时候为length -1
}
}
/**
* 建立大顶堆
* @param a
*/
private static void buildHeap(Comparable[] a){
int length = a.length ;
for(int i = length/2 -1 ; i >= 0 ;i--)
adjust(a,i,length);
}
/*@name adjust
* @Function: 调整以节点 i 为顶点的堆
*/
private static void adjust(Comparable[] a ,int i,int length){
int left = 2*i + 1,
right= 2*i + 2 ;
if(left >= length && right >= length) return ;
int max = i;
if(left < length && less(a[max],a[left]))
max = left;
if(right <length && less(a[max],a[right]))
max = right ;
if(max!=i){
exch(a,i,max);
adjust(a,max,length);
}
}
public static void main(String[] args){
int N = 10 ;
Integer[] a = new Integer[N];
Random random = new Random();
for(int i = 0; i < N; i++)
a[i] = random.nextInt(30);
sort(a);
show(a);
}
}
三.归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并过程为:比较a[i]和b[j]的大小,若a[i]≤b[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素b[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。(以上摘自百科)
算法步骤:
1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4.重复步骤3直到某一指针达到序列尾
5.将另一序列剩下的所有元素直接复制到合并序列尾
代码来源:百科Java未测试
package algorithm;
public class MergeSort {
// private static long sum = 0;
/**
* * <pre>
* * 二路归并
* * 原理:将两个有序表合并和一个有序表
* * </pre>
* *
* * @param a
* * @param s
* * 第一个有序表的起始下标
* * @param m
* * 第二个有序表的起始下标
* * @param t
* * 第二个有序表的结束小标
* *
*/
private static void merge(int[] a, int s, int m, int t) {
int[] tmp = new int[t - s + 1];
int i = s, j = m, k = 0;
while (i < m && j <= t) {
if (a[i] <= a[j]) {
tmp[k] = a[i];
k++;
i++;
} else {
tmp[k] = a[j];
j++;
k++;
}
}
while (i < m) {
tmp[k] = a[i];
i++;
k++;
}
while (j <= t) {
tmp[k] = a[j];
j++;
k++;
}
System.arraycopy(tmp, 0, a, s, tmp.length);
}
/**
* *
* * @param a
* * @param s
* * @param len
* * 每次归并的有序集合的长度
*/
public static void mergeSort(int[] a, int s, int len) {
int size = a.length;
int mid = size / (len << 1);
int c = size & ((len << 1) - 1);
// -------归并到只剩一个有序集合的时候结束算法-------//
if (mid == 0)
return;
// ------进行一趟归并排序-------//
for (int i = 0; i < mid; ++i) {
s = i * 2 * len;
merge(a, s, s + len, (len << 1) + s - 1);
}
// -------将剩下的数和倒数一个有序集合归并-------//
if (c != 0)
merge(a, size - c - 2 * len, size - c, size - 1);
// -------递归执行下一趟归并排序------//
mergeSort(a, 0, 2 * len);
}
public static void main(String[] args) {
int[] a = new int[]{4, 3, 6, 1, 2, 5};
mergeSort(a, 0, 1);
for (int i = 0; i < a.length; ++i) {
System.out.print(a[i] + " ");
}
}
}
代码来源::http://blog.youkuaiyun.com/yunshuixiliu/article/details/21015161未测试
package sort;
import java.util.Random;
public class MerageSort extends AbstractSort {
private static Comparable[] temp ;
public static void sort(Comparable[] a){
temp = new Comparable[a.length] ;
sort(a,0,a.length - 1);
}
/**
* 自底向上归并
* @param a
*/
public static void sortBU(Comparable[] a){
temp = new Comparable[a.length] ;
int N = a.length ;
for(int step = 1 ;step < N ;step+=step )
for(int left = 0 ;left < N -step ;left += step +step)
merage(a,left,left+step-1,Math.min(left+step+step-1, N-1));
}
/**
* 自顶向下归并排序
* @param a
* @param left
* @param right
*/
private static void sort(Comparable[] a ,int left ,int right){
if(left >= right) return ;
int mid = left + (right - left ) / 2;
sort(a,left,mid);
sort(a,mid+1,right) ;
// merage(a,left,mid,right);
merageWithoutTemp(a,left,mid,right);
}
/**
* 非原地归并排序,需要辅助数组
* @param a
* @param left
* @param mid
* @param right
*/
private static void merage(Comparable[] a ,int left,int mid,int right){
int i = left , j = mid + 1;
for(int k = left ; k <= right ; k++)
temp[k] = a[k] ;
for(int k = left ; k <= right ; k++){
if(i > mid) a[k] = temp[j++];
else if(j > right ) a[k] = temp[i++] ;
else if(less(temp[i],temp[j])) a[k] = temp[i++];
else a[k] = temp[j++] ;
}
}
/**
* 原地归并排序,不需要辅助数组,节省空间
* @param a
* @param left
* @param mid
* @param right
*/
private static void merageWithoutTemp(Comparable[] a ,int left ,int mid , int right ){
int i = left ,j = mid + 1,k =right ;
int step = 0 ;
while(i < j && j <= k){
while(i < j && less(a[i],a[j])) i++;
while(j <= k && less(a[j],a[i])){j++;step++;}
exchang(a,i,j,step);
}
}
private static void exchang(Comparable[] a, int i, int j, int step) {
reverse(a,j-step,j-1);
reverse(a,i,j-step-1);
reverse(a,i,j-1);
}
private static void reverse(Comparable[] a, int begin ,int end){
while(begin <end)
exch(a,begin++,end--);
}
public static void main(String[] args){
int N = 10 ;
Integer[] a = new Integer[N];
Random random = new Random();
for(int i = 0; i < N; i++)
a[i] = random.nextInt(30);
sortBU(a);
show(a);
}
}
四.二分查找算法
二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(logn) 。
五.BFPRT(线性查找算法)
算法步骤:
1.将n个元素每5个一组,分成n/5(上界)组。
2.取出每一组的中位数,任意排序方法,比如插入排序。
3.递归的调用selection算法查找上一步中所有中位数的中位数,设为x,偶数个中位数的情况下设定为选取中间小的一个。
4.用x来分割数组,设小于等于x的个数为k,大于x的个数即为n-k。
5.若i==k,返回x;若i