数据结构-Java实现-排序

  1. 直接插入排序
  2. 希尔排序(二分插入)
  3. 简单选择排序
  4. 堆排序
  5. 归并排序
  6. 快速排序
  7. 冒泡排序
  8. 桶式排序(基数排序)

1、直接插入排序

插入排序由N-1趟排序组成,对于p=1到p=N-1趟,保证位置0到p上的元素为已排序状态。在第p趟,将位置p上的元素向左移动到正确位置。
S(N)=O(N^2)

public static <AnyType extends Comparable<? super AnyType>>
void insertionSort(AnyType[] a)
{
    int j;

    for(int p=1; p<a.length; p++)
    {
        AnyType tmp = a[p];  //tmp用来存储位置p上的元素
        for(j=p;j>0&&tmp.compareTo(a[j-1])<0;j--)  //j指针指向p,然后左移直至右边的元素>=a[p]
        a[j] = a[j-1];  //关键步骤就是边移动指针边交换元素,类似排队时向前一个一个插队
        a[j] =tmp;  //找到正确位置以后a[j]就不能为a[j-1]咯
    }
}

2、希尔排序 (二分插入)

希尔排序通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到比较相邻元素的最后一趟排序为止。设增量序列为h[n], h[t]=N/2, h[k]=h[k+1]/2。即从数组长度的一半开始为原始增量,不断二分直至为1.

public static <AnyType extends Comparable<? super AnyType>>
void shellSort(AnyType[] a)
{
    int j;
    for(int gap=a.length/2; gap>0; gap/=2)  //不断二分直至为1
        for(int i=gap; i<a.length; i++)  //i指针指向gap并后移
        {
            AnyType tmp = a[i];
            for(j=i; j>=gap && tmp.compareTo(a[j-gap])<0; j-=gap)  //j指针执行向前比较,交换相距gap的元素的值
                a[j]=a[j-gap];  //同插入排序的非显示交换
            a[j]=tmp;
        }
} 

3、简单选择排序

简单选择排序类似冒泡排序,但是不需要依次相邻交换,而是新建一个临时变量存储最小值下标,不断缩小范围寻找最小值,然后依次排列。

private static<AnyType extends Comparable<? super AnyType>>
void choiceSort(AnyType[] a)
{
    for int(i=0; i<a.length; i++)  //排序的趟数
    {
        int min=i;  //当前下标初始化为最小值下表

        for(int j=i+1;j<a.length;j++)  //寻找最小值,重置min
        {
            if( (a[min]).compareTo(a[j])>0 ){
                min=j;
            }
        }
        if(i!=min){  //找到不同的最小值,a[min]和a[i]互换
            AnyType[] tmp=a[min];
            a[min]=a[i];
            a[i]=tmp;
        }
    }
}

4、堆排序

堆排序就是利用了二叉堆这个特殊数据结构的特性–排列规律,每次能够删除根节点(最大或最小值)。每次删除根节点后,再将根节点放在尾部以实现排序。简而言之就是对未排序部分做下滤操作后将根节点放于尾部。

/**这里要利用到堆结构排列在数组中后的特殊特性。不理解可以先画个堆自己插入、删除走一遍,观察在数组中的访问步骤。
  *对于数组中任一位置i上的元素,其左儿子在位置2i上,它的父亲在位置[i/2]上。(0位置为空的情况下)
  */
//堆排序
private static int leftChild(int i)
{
    return 2*i+1;
}

private static <AnyTYpe extends Comparable<? super AnyType>>
void percDown(AnyType[] a, int i, int n)  //三个参数,数组对象,节点,数组长度范围
{
    int child;
    AnyType tmp;

    for(tmp=a[i]; leftChild(i)<n;i=child;)
    {
        child=leftChild(i);  //child类似指针指向左子节点,开始遍历
        if(child!=n-1&&a[child].compareTo(A[child+1]<0)  //只要小于右边就一直右移,找到最大的字节点
            child++;
        if(tmp.compareTo(a[child]<0)  //如果i小于它的字节点
            a[i]=a[child];  //自节点上滤
        else
            break;
    }
    a[i]=tmp;  //相当于a[child]=tmp;就是将a[i]值跟它的字节点互换
}

public static<AnyType extends Comparable<? super AnyType>>
void heapSort(AnyType[] a)
{
    for(int i=a.lenght/2;i>=0;i--)  //根据二叉堆性质--任一位置i上的元素的父亲在[i/2]上,即从堆结构的尾部依次遍历非叶子节点,直到根节点
        percDown(a,i,a.length);  //依次对非叶子节点进行上滤,以此来构建堆
    for(int i=a.length-1;i>0;i--)  //这里的i--作用是取出最大值后范围就缩小了
    {
        swapReferences(a,0,i);  //存放在0位置的根节点,把根节点的值跟末尾i位置的值互换,这一步算作删除最大值操作,或者叫取出最大值
        percDown(a,0,i);  //取出后根节点不满足二叉堆性质了,所以前面i个值需要重新构建二叉堆,也就是重新上滤
    }
}

5、归并排序

归并排序就是将两个有序数组合并,双指针同时遍历两个数组,比较大小并依次排放在第三个新建的数组中。通过递归地将数组不断二分再分别合并,最终会二分至只有1个元素的数组从而完成排序。

//将两个有序数组进行组合的merge方法
public static<AnyType extends Comparable<? super AnyTYpe>>
void merge(AnyType[] a,AnyType[] tmpArray,int leftPos,int rightPos, int rightEnd)
{
    int leftEnd = rightPos - 1;
    int tmpPos = leftPos;
    int numElements = rightEnd - leftPos + 1;

    while(leftPos<=leftEnd&&rightPos<=rightEnd) //leftPos和rightPos双指针在范围内同时右移进行比较,将小的数存入tmpArray
        if(a[leftPos].compareTo(a[rightPos])<=0)
            tmpArray[tmpPos++] = a[leftPos++];
        else
            tmpArray[tmpPos++] = a[rightPos++];
    //当上述while循环结束,以下两个while循环检查还未用完的数组,将余下部分拷贝到tmpArray中
    while(leftPos <= leftEnd)
        tmpArray[tmpPos++] = a[leftPos++];
    while(rightPos <= rightEnd)
        tmpArray[tmpPos++] = a[rightPos++];
    //将tmpArray元素拷回
    for(int i=0;i<numElements;i++,rightEnd--)
        a[rightEnd]=tmpArray[rightEnd];     
}
//归并操作的四参数重载方法
private static<AnyType extends Comparable<? super AnyType>>
void mergeSort(AnyType[] a, AnyTYpe[] tmpArray, int left, int right)
{
    if(left<right)
    {
        int center = (left+right)/2; 
        //递归调用执行合并排序操作,不断划分为更小的有序数组(2个数)
        mergeSort(a,tmpArray,left,center);  
        mergeSort(a,tmpArray,center+1,right);
        //合并初始的两个最大有序数组
        merge(a,tmpArray,left,center+1,right);
    }
}
//归并操作的单参数重载方法
public static<AnyType extends Comparable<? super AnyType>>
void mergeSort(AnyType[] a)
{
    AnyType[] tmpArray = (AnyType[]) new Comparable[a.length];  //根据待排序数组长度新建临时数组
    mergeSort(a,tmpArray,0,a.length-1);  //根据待排序数组提取四参数传入
}

6、快速排序

快速排序即选取枢纽元,将比它小的放在左边,大的放在右边,然后递归地对左右两边进行快排。关键点在于选取枢纽元的方法,这里采用三数分割法,选取的同时将三个数排序,将枢纽元放在n-1处,可以缩小排序范围。

//快速排序
public stativ<AnyType extends Comparable<? super AnyType>>
void quickSort(AnyType[] a)
{
    quickSort(a,0,a.length-1);
}
//三数分割法
private static<AnyType extends Comparable<? super AnyType>>
void median3(AnyType[] a,int left, int right)
{
    int center=(left+right)/2;  //确定center值
    if(a[center].compareTo(a[left]<0)  //如果center<left
        swapReferences(a, left, center);  //调换center、left位置
    if(a[right].compareTo(a[left])<0)  //如果right<left
        swapReferences(a,left,right);  //调换right、left位置 , 这样能够确保最小的放在left处
    if(a[right].compareTo(a[center]<0)  //如果right<center
        swapReferences(a,center,right);  //调换right、center位置 ,这样就能保证最大的放在right处,即left<center<right排列
    swapReferences(a,center,right-1);  //将center放在right-1的位置
    return a[right-1];  //返回三数中值
}
//快排主函数
private static<AnyType extends Comparable<? super AnyType>>
void quickSort(AnyType[] a,int left, int right)
{
    //定义CUTOFF为10,相差10以内直接插入排序吧。。
    final CUTOFF = 10;
    if(left+CUTOFF<=right)
    {
        //取中值pivot
        AnyType pivot = median3(a,left,right);
        //i指针从left开始,j指针从right-1开始
        int i=left, j=right-1;
        for( ; ; )
        {
            while(a[++i].compareTo(pivolt)<0){}  //i指针右移寻找较大的数(>=)
            while(a[--j].compareTo(pivolt)>0){}  //j指针左移寻找较小的数(<=)
            if(i<j)  //i、j指针没有相遇则交换i、j指向的值,即大的放右边小的放左边
                swapReferences(a,i,j);
            else  //相遇则跳出
                break;
        }
        //最后一步,将i指向的数与放在尾部的中值互换,完成小的在中值左边,大的在中值右边
        swapReferences(a,i,right-1);
        //递归地分别对左右两边快排
        quickSort(a,left,i-1);
        quickSort(a,i+1,right);
    }
    else
        insertionSort(a,left,right);
}

7、 冒泡排序

冒泡排序和选择排序类似,但是没有建立临时变量,而是通过相邻交换将最大或最小值不断后移达到依次排序的效果。

private static<AnyType extends Comparable<? super AnyType>>
void bubbleSort(AnyType[] a)
{
    int len=a.length-1;
    for(i=0;i<len;i++)  //排序的趟数
        for(j=0;j<len-i-1;j++)  //j的范围不断缩小,第i趟排列0到len-i-1个数
        {
            //将最大的数依次后移放到最后,可以理解为每次最大的泡向上冒
            if( (a[j]).compareTo(a[j+1])>0 )
            {
                AnyType[] temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
            }
        }
}

桶式排序(基数排序)

占坑
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值