您的位置:首页 > 编程语言 > Java开发

java排序方法

2015-08-30 00:36 701 查看
此节介绍排序方法

1,冒泡排序

2,选择排序

3,插入排序

4,希尔排序

5,快速排序

6,归并排序

一,冒泡排序

算法描叙:

设待排序记录序列中的记录个数为n

一般地,第i趟起泡排序从1到n-i+1

依次比较相邻两个记录的关键字,如果发生逆序,则交换之。

其结果是这n-i+1个记录中,关键字最大的记录被交换到第n-i+1的位置上,最多作n-1趟。

二,选择排序

算法描叙:

首先通过n-1次比较,从n个数中找出最小的, 将它与第一个数交换——第一趟选择排序,结果最小的数被安置在第一个元素位置上。

再通过n-2次比较,从剩余的n-1个数中找出关键字次小的记录,将它与第二个数交换——第二趟选择排序。

重复上述过程,共经过n-1趟排序后,排序结束。

三,插入排序

算法描叙

记录存放在数组R[0….n-1]中,排序过程的某一中间时刻,R被划分成两个子区间R[0…i-1]和R[i….n-1],其中:前一个子区间是已排好序的有序区;后一个子区间则是当前未排序的部分。

基本操作:

将当前无序区的第1个记录R[i]插入到有序区R[0….i-1]中适当的位置,使R[0…i]变为新的有序区

操作细节:

当插入第i(i≥1)个对象时, 前面的r[0], r[1], …, r[i-1]已经排好序。

四,希尔排序

算法描叙:

先取定一个小于n的整数gap1作为第一个增量,把整个序列分成gap1组。所有距离为gap1的倍数的元素放在同一组中,在各组内分别进行排序(分组内采用直接插入排序或其它基本方式的排序)。

然后取第二个增量gap2<gap1,重复上述的分组和排序。

依此类推,直至增量gap=1,即所有元素放在同一组中进行排序为止。

算法分析:

开始时 gap 的值较大, 子序列中的元素较少, 排序速度较快。

随着排序进展, gap 值逐渐变小, 子序列中元素个数逐渐变多,由于前面大多数元素已基本有序, 所以排序速度仍然很快。

分组后n值减小,n²更小,而T(n)=O(n²),所以T(n)从总体上看是减小了。

Gap的取法有多种。 shell 提出取 gap = n/2 ,gap = gap/2 ,…,直到gap = 1。gap若是奇,则gap=gap+1

五,快速排序

算法描叙:

任取待排序记录序列中的某个记录(例如取第一个记录)作为基准(枢),按照该记录的关键字大小,将整个记录序列划分为左右两个子序列

左侧子序列中所有记录的关键字都小于或等于基准记录的关键字

右侧子序列中所有记录的关键字都大于基准记录的关键字

基准记录则排在这两个子序列中间(这也是该记录最终应安放的位置)。

然后分别对这两个子序列重复施行上述方法,直到所有的记录都排在相应位置上为止。

基准记录也称为枢轴(或支点)记录。取序列第一个记录为枢轴记录,其关键字为Pivotkey。指针low指向序列第一个记录位置,指针high指向序列最后一个记录位置。

算法分析:

快速排序是一个递归过程,快速排序的趟数取决于递归树的高度。

如果每次划分对一个记录定位后, 该记录的左侧子序列与右侧子序列的长度相同, 则下一步将是对两个长度减半的子序列进行排序, 这是最理想的情况。

六,归并排序

算法描叙:

设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列长度为1。

两两合并,得到 n/2 个长度为2或1的有序子序列。

再两两合并,……如此重复,直至得到一个长度为n的有序序列为止。

package cn.hncu.sortMethods;

public class SortMethods {

/*输出数组中的元素*/
private static void print(int[] a) {
for(int num: a){
System.out.print(num+"\t");
}
System.out.println();
}
private static void swap(int[] a, int i, int j) {
int temp;
temp =a[i];
a[i] = a[j];
a[j] = temp;
}

public static void main(String[] args) {
int a[] = {0,21,25,49,25,16,15,8,-2,0,-9,67,34,5,12,40};
//1-1冒泡排序
bubbleSort(a);
//1-2优化的冒泡排序
//bubbleSort2(a);

//2选择排序
//selectSort(a);

//3-1直接插入排序
//insertSort(a);

//3-2用二分优化插入排序
//binaryInsertSort(a);

//4 希尔排序
//shellSort(a);

//5 快速排序
//quickSort(a,0,a.length-1);

//6 归并排序
//mergeSort(a,0,a.length-1);

print(a);
}

private static void mergeSort(int[] a, int left, int right) {
if(left<right){//至少有2个元素
int mid = (left+right)/2; //二分,取中点
//把序列拆分成两个子序列:[left,mid] 和  [mid+1,right]
//同时还要对分解后的子序列分别进行递归“归并排序”
mergeSort(a,left,mid);
mergeSort(a,mid+1,right);

//把前面两个已经排好序的子序列进行归并
int b[] = new int[a.length];
merge(a,b,left,mid,right);
copyArray(a,b,left,right);
}
}

private static void copyArray(int[] a, int[] b, int left, int right) {
for(int i=left;i<=right;i++){
a[i] = b[i];
}
}
//把两个已经排好序的子序列(a[left,mid]和a[mid+1,right]) 合并成一个 ( b[left,right] )
private static void merge(int[] a, int[] b, int left, int mid, int right) {
int p = left;
int r=mid+1;
int k=left;
while( p<=mid && r<=right ){
if(a[p]<=a[r]){
b[k++] = a[p++];
}else{
b[k++] = a[r++];
}
}
//此时,肯定有一个子序列中的元素全部移到b[]数组,因此,只要把还未移完的子序列当中的所有剩余元素直接对拷到数组b[]当中即可
if(p>mid){//左子序列已经完成。因此剩下的是右序列,对拷右序列当中的剩余元素即可
for(int i=r;i<=right;i++){
b[k++]=a[i];
}
}else{//对拷左子序列中的剩余元素
for(int i=p;i<=mid;i++){
b[k++]=a[i];
}
}
}

private static void quickSort(int[] a, int p, int r) {
if(p<r){
//把数组划分成两个子数组和一个元素(枢轴):
//用枢轴a[q]把整数数组划分成 ==>  a[p,q-1] , a[q] , a[q+1,r]
int q = partition(a,p,r); //a[q]
quickSort(a,p,q-1);//排左边的子数组a[p,q-1]
quickSort(a,q+1,r);//排右边的子数组a[q+1,r]
}

}
private static int partition(int[] a, int p, int r) {
//优化:采用随机选择策略确定枢轴----随机选取数组当中的一个元素,和第一个元素进行交换。之后,以第一个元素作为枢轴进行划分
int rand = (int)(Math.random()*(r-p));//rand为区间内的随机序号(第几个)//p=10000, r=15000
swap(a,p,p+rand);

int i=p;//第一个元素定为枢轴
int j=r+1;
int x=a[p];

while(true){
while(a[++i]<x && i<r);//定位指针i,找比x大的元素 <--为的是找要交换到右边的"非法"元素
while(a[--j]>x);//定位指针j <--为的是找要交换到左边的"非法"元素
if(i>=j){
break;
}
swap(a,i,j);
}
swap(a,p,j);//枢轴a[p]要换到中间位置
return j;
}

//4 希尔排序
private static void shellSort(int[] a) {
//进行分组,初始步长设为数组长度的一半即n/2,然后依次减半,直到最后取1
for(int gap=(a.length+1)/2;gap>0;){
//组内排序
for(int i=0;i<a.length-gap;i++){//定位到每一个元素
for(int j=i;j<a.length-gap;j+=gap){
if(a[j]>a[j+gap]){
swap(a,j,j+gap);
}
}
}
//for循环的修正
if(gap>1){
gap = (gap+1)/2;
}else if(gap==1){
break;
}
}

}

//3-2用二分优化插入排序
private static void binaryInsertSort(int a[]){
for(int i=0;i<a.length-1;i++){
int temp=a[i+1];
int low=0;
int high=i;
int mid;
//在low与 high之间的区域内进行二分查找,以确定新元素的插入位置
while(low<=high){
mid = (high+low)/2;
if(a[mid]>temp){//若待插入的数小于中间元素a[mid],则目标落于左半区
high = mid-1;
}else{//若待插入的数大于等于中间元素a[mid],则目标落于右半区
low= mid+1;
}
}
//搜索的最后一个小区间的high位置即是查找目标,因此新元素的插入位置即是high+1
//把原来从high到i范围内的元素依次往后移一个位置
for(int j=i;j>high;j--){
a[j+1] = a[j];
}
a[high+1] = temp;
}

}

//3-1直接插入排序
private static void insertSort(int[] a) {
for(int i=0;i<a.length-1;i++){
int temp=a[i+1];
int j=i;
//插入第i个数
//从后往前搜,发现a[j]>temp时,则把a[j]后移到j+1的位置,继续往前搜。
while(a[j]>temp){
a[j+1]=a[j];
j--;
if(j<0){
break;
}
}
//否则即a[j]<=temp时,直接把待插入的数放到a[j+1]处
a[j+1]=temp;
}
}

//2选择排序
private static void selectSort(int[] a) {
for(int i=0;i<a.length-1;i++){
int j,k;
for(j=i+1,k=i;j<a.length;j++){
if(a[j]<a[k]){
k=j;
}
}
if(k!=i){
swap(a,i,k);
}
}
}

/*1-1冒泡排序*/
private static void bubbleSort(int[] a) {
//冒n-1次,每一次排一个数,最后一个不用排
for(int i=0;i<a.length-1;i++){
//第i趟,从1~n-i-1,两两相邻的数进行判断,若逆顺则交换
for(int j=0;j<a.length-i-1;j++){
if(a[j]>a[j+1]){//升序
swap(a, j, j+1);
}
}
}
}
/*1-2冒泡排序优化*/
private static void bubbleSort2(int[] a) {
boolean flag=false;//表示整个序列还没排好
//冒n-1次,每一次排一个数,最后一个不用排
for(int i=0;i<a.length-1;i++){

flag = true;//假设整个序列已经完成排序
for(int j=0;j<a.length-i-1;j++){
if(a[j]>a[j+1]){
swap(a, j, j+1);
//如果有交换,说明前面的假设不成立
flag = false;
}
}
if(flag){//如果前面的假设成立即整个序列已经排好序,则函数返回
return;
}
}
}

}


ppt 文档 链接:http://pan.baidu.com/s/1c0vzh9u 密码:23yt


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: