排序算法整理
在写这篇文章的时候我还是初学者--希望能通过博客观察自己的成长
首先声明:算法均参考自 <数据结构教程>--李春葆著
所用到的数据结构---这里为简便,使用简单的int值
class ElemType { ElemType(int data) { this.data=data; } public int data; }
main函数
public static void main(String[] args) { ElemType [] R=new ElemType[10]; for(int i=0;i<10;i++) { R[i]=new ElemType((int)(Math.random()*10)); } for(ElemType r:R) System.out.print(r.data); System.out.println(); quicksort(R,0,9); //快速排序 insertSort(R,10); //直接插入排序 insertSort2(R,10); //折半插入排序 shellSort(R,10); //希尔排序 bubbleSort(R,10); //冒泡排序 selectSort(R,10); //直接选择排序 heapSort(R,10); //堆排序(数据序列的下标从1开始) for(ElemType r:R) System.out.print(r.data); }
插入排序: 包括直接插入排序,折半插入排序,希尔排序
static void insertSort(ElemType[]R,int n)//直接插入排序 { int i,j; ElemType tmp; for(i=1;i<n;i++) { tmp=R[i]; j=i-1; //从右向左在有序区R[0...i-1]中找R[i]的位置 while(j>=0&&R[j].data>tmp.data)//当不成立的时候,j即需要插入的元素的位置 { R[j+1]=R[j];//将关键字大于R[i].data的元素后移 j--; } R[j+1]=tmp; //在J+1处插入R[i]; } }
static void insertSort2(ElemType[] R, int n)//折半插入排序 { int i, j, low, high, mid; ElemType tmp; for (i = 1; i < n; i++) { tmp = R[i]; //将R[i]保存到tmp中 low = 0; high = i - 1; while (low <= high) //在R[low...high]中折半查找有序插入的位置 { mid = (low + high) / 2; //取中间位置 if (tmp.data < R[mid].data) high = mid - 1; //插入点在左半区 else low = mid + 1; //插入点右半区 } for(j=i-1;j>=high+1;j--) //元素后移 R[j+1]=R[j]; R[high+1]=tmp; //插入 } }
static void shellSort(ElemType[] R,int n) //希尔排序 { int i,j,gap; ElemType tmp; gap=n/2; //增量置初值 while(gap>0) { for(i=gap;i<n;i++) //对所有相隔gap位置的元素组采用直接插入排序 { tmp=R[i]; j=i-gap; while(j>=0&&tmp.data<R[j].data) //对相隔gap位置的元素组进行排序 { R[j+gap]=R[j]; j=j-gap; } R[j+gap]=tmp; } gap=gap/2; //减少增量 } }
交换排序: 包括冒泡排序和快速排序
static void bubbleSort(ElemType []R ,int n)//冒泡排序 { int i,j; ElemType tmp; for(i=0;i<n-1;i++) { boolean flag=false; //改进 for(j=n-1;j>i;j--) //逐个比较,依次将无序区中最小元素移动到有序区的队首 if(R[j].data<R[j-1].data) { tmp=R[j]; R[j]=R[j-1]; R[j-1]=tmp; flag=true; } if(!flag) return; //本次没有发生交换--提前结束排序 } }
static void quicksort(ElemType[] R,int s,int t)//快速排序(s,t分别是头尾) { int i=s,j=t; //i,j分别将头尾保存起来 ElemType tmp; //用于比较,传值 if(s<t) //可以理解为 s!=t { tmp=R[s]; //将头保存起来,其实这个是作为参照值,可以任选 为方便 将头作为参照对象 while(i!=j) //i!=j的时候意味着没有遍历完成(目的要将范围内小的放左边,大的放右边 i==j的时候 i即中间值) { while(j>i&&R[j].data>=tmp.data)//j向右遍历,直到i==j或者出现了tmp>R[j]的情况--执行交换操作 j--; R[i]=R[j]; //找到一个小于tmp.data的R[j]-- R[i]跟R[j]交换(假如R[i]=) while(i<j&&R[i].data<=tmp.data)//i向左遍历,直到i==j或者出现了tmp<R[i]的情况--执行交换操作 i++; R[j]=R[i]; } R[i]=tmp; quicksort(R,s,i-1); quicksort(R,i+1,t); //i为中间值,所以只需要将i左边和i右边的处理即可 } }
选择排序: 包括直接选择排序和堆排序
static void selectSort(ElemType[]R ,int n)//直接选择排序 { int i,j,k; ElemType tmp; for(i=0;i<n-1;i++) //做第i趟排序 { k=i; for(j=i+1;j<n;j++) //在当前无序区R[i...n-1]中选择key最小的R[k] if(R[j].data<R[k].data) k=j; //k记下目前找到的最小关键字所在的位置 if(k!=j) //交换R[i]和R[k] { tmp=R[i]; R[i]=R[k]; R[k]=tmp; } } }
//堆排序 static void sift(ElemType []R ,int low, int high)//调整堆 { int i=low,j=2*i; //R[j]是R[i]的左孩子 ElemType tmp=R[i]; while(j<=high) { if(j<high&&R[j].data<R[j+1].data) //若有孩子较大,把j指向右孩子 j++; if(tmp.data<R[j].data) { R[i]=R[j]; //将R[j]调整到双亲节点位置上 i=j; //修改i和j值,以便继续向下筛选 j=2*i; } else break; //筛选结束 } R[i]=tmp; //被筛选节点的值放入最终位置 } static void heapSort(ElemType[] R,int n)//堆排序(注意,为了与二叉树的顺序结构存储一致,堆排序的数据序列的下标从1开始) { int i; ElemType tmp; for(i=n/2;i>=1;i--) //循环建立初始堆 sift(R,i,n); for(i=n;i>=2;i--) //进行n-1躺堆排序,每一趟堆排序的元素个数减一 { tmp=R[1]; //将最后一个元素同当前区间内R[1]对换 R[1]=R[i]; R[i]=tmp; sift(R,1,i-1); //筛选R[1]节点,得到i-1个节点的堆 } } }
这里要注意一下,由于堆排序的数据序列下标从1开始,因此数据格式跟其他排序不一样
这里贴出一个专门用于堆排序测试的main函数
public static void main(String[] args) { ElemType [] R=new ElemType[11]; R[0]=new ElemType(-1); for(int i=1;i<11;i++) { R[i]=new ElemType((int)(Math.random()*10)); } for(int i=1;i<11;i++) System.out.print(R[i].data); System.out.println(); heapSort(R,10); for(int i=1;i<11;i++) System.out.print(R[i].data); }
归并排序:
public static void mergeSort(ElemType R[],int n)//自底向上的二路归并算法 { int length; for(length=1;length<n;length=2*length) //进行Log(n)趟归并 MergePass(R,length,n); } public static void MergePass(ElemType[]R,int length,int n)//对整个表进行一趟归并 { int i; for(i=0;(i+2*length-1)<n;i=i+2*length) //归并length长的两相邻子表 Merge(R,i,i+length-1,i+2*length-1); if(i+length-1<n) //余下两个子表,后者长度小于length Merge(R,i,i+length-1,n-1); //归并这两个子表 } public static void Merge(ElemType R[],int low ,int mid ,int high) { ElemType[] Rt=new ElemType[R.length]; int i=low,j=mid+1,k=0; //k是R1的下标,i,j分别是第1,2段的下标 while(i<=mid&&j<=high) //在第一第二段均未扫描完成时循环 if(R[i].data<=R[j].data) //将第一段中的元素放入R1中 { Rt[k]=R[i]; i++;k++; } else{ //将第二段中的元素放入R1中 Rt[k]=R[j]; j++;k++; } while(i<=mid) //将第一段余下部分复制到R1中 { Rt[k]=R[i]; i++;k++; } while(j<=high) //将第二段余下部分复制到R1中 { Rt[k]=R[j]; j++;k++; } for(k=0,i=low;i<=high;k++,i++)//将R1复制回R中 R[i]=Rt[k]; }