leetcode算法题中主要要求手撕的三种排序算法 快速排序,归并排序,堆排序算法模板子

快速排序,归并排序,堆排序模板java代码

目录

1、快速排序

快速排序原理:

 切分原理:

源代码:

2、归并排序

归并排序原理:

归并原理

 源代码:

3、堆排序

堆排序原理

堆排序过程

 源代码


1、快速排序

快速排序原理:


1.首先设定一个分界值,通过该分界值将数组分成左右两部分;
2.将大于或等于分界值的数据放到到数组右边,小于分界值的数据放到数组的左边。此时左边部分中各元素都小于
或等于分界值,而右边部分中各元素都大于或等于分界值;

3.然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两
部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4.重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当
左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了。

 切分原理:


把一个数组切分成两个子数组的基本思想:
1.找一个基准值,用两个指针分别指向数组的头部和尾部;
2.先从尾部向头部开始搜索一个比基准值小的元素,搜索到即停止,并记录指针的位置;
3.再从头部向尾部开始搜索一个比基准值大的元素,搜索到即停止,并记录指针的位置;
4.交换当前左边指针位置和右边指针位置的元素;
5.重复2,3,4步骤,直到左边指针的值大于右边指针的值停止。

源代码:

//排序代码
public class Quick 
{
public static void sort(Comparable[] a) 
{
    int lo = 0;
    int hi = a.length - 1;
    sort(a, lo,hi);
}
private static void sort(Comparable[] a, int lo, int hi) 
{
    if (hi<=lo)
    {
        return;
    }
    //对a数组中,从lo到hi的元素进行切分
    int partition = partition(a, lo, hi);
    //对左边分组中的元素进行排序
    //对右边分组中的元素进行排序
    sort(a,lo,partition-1);
    sort(a,partition+1,hi);
}
public static int partition(Comparable[] a, int lo, int hi) 
{
    Comparable key=a[lo];//把最左边的元素当做基准值
    int left=lo;//定义一个左侧指针,初始指向最左边的元素
    int right=hi+1;//定义一个右侧指针,初始指向左右侧的元素下一个位置
    //进行切分
    while(true)
    {
        //先从右往左扫描,找到一个比基准值小的元素
        while(less(key,a[--right]))
        {//循环停止,证明找到了一个比基准值小的元素
            if (right==lo)
            {
                break;//已经扫描到最左边了,无需继续扫描
            }
        }
        //再从左往右扫描,找一个比基准值大的元素
        while(less(a[++left],key))
        {//循环停止,证明找到了一个比基准值大的元素
            if (left==hi)
            {
            break;//已经扫描到了最右边了,无需继续扫描
            }
        }
        if (left>=right)
        {
            //扫描完了所有元素,结束循环
            break;
        }
        else
        {
            //交换left和right索引处的元素
            exch(a,left,right);
        }
    }
    //交换最后rigth索引处和基准值所在的索引处的值
    exch(a,lo,right);
    return right;//right就是切分的界限
}
/*
数组元素i和j交换位置
*/
private static void exch(Comparable[] a, int i, int j) 
{
    Comparable t = a[i];
    a[i] = a[j];
    a[j] = t;
}
/*
比较v元素是否小于w元素
*/
private static boolean less(Comparable v, Comparable w) 
{
    return v.compareTo(w) < 0;
}
}
//测试代码
public class Test 
{
    public static void main(String[] args) throws Exception 
    {
        Integer[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 8};
        Quick.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

2、归并排序

归并排序原理:

1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是 1为止。

2.将相邻的两个子组进行合并成一个有序的大组;

3.不断的重复步骤2,直到最终只有一个组为止。

归并原理

 源代码:

//排序代码
public class Merge 
{
    private static Comparable[] assist;//归并所需要的辅助数组
    /*
    对数组a中的元素进行排序
    */
    public static void sort(Comparable[] a) 
    {
        assist = new Comparable[a.length];
        int lo = 0;
        int hi = a.length-1;
        sort(a, lo, hi);
    }
    /*
    对数组a中从lo到hi的元素进行排序
    */
    private static void sort(Comparable[] a, int lo, int hi) 
    {
        if (hi <= lo) 
        {
            return;
        }
        int mid = lo + (hi - lo) / 2;
        //对lo到mid之间的元素进行排序;
        sort(a, lo, mid);
        //对mid+1到hi之间的元素进行排序;
        sort(a, mid+1, hi);
        //对lo到mid这组数据和mid到hi这组数据进行归并
        merge(a, lo, mid, hi);
    }
    /*
    对数组中,从lo到mid为一组,从mid+1到hi为一组,对这两组数据进行归并
    */
    private static void merge(Comparable[] a, int lo, int mid, int hi) 
    {
        //lo到mid这组数据和mid+1到hi这组数据归并到辅助数组assist对应的索引处
        int i = lo;//定义一个指针,指向assist数组中开始填充数据的索引
        int p1 = lo;//定义一个指针,指向第一组数据的第一个元素
        int p2 = mid + 1;//定义一个指针,指向第二组数据的第一个元素
        //比较左边小组和右边小组中的元素大小,哪个小,就把哪个数据填充到assist数组中
        while (p1 <= mid && p2 <= hi) 
        {
            if (less(a[p1], a[p2])) 
            {
                assist[i++] = a[p1++];
            } 
            else 
            {
                assist[i++] = a[p2++];
            }
        }
        //上面的循环结束后,如果退出循环的条件是p1<=mid,则证明左边小组中的数据已经归并完毕,如                    果退出循环的条件是p2<=hi,则证明右边小组的数据已经填充完毕;
        //所以需要把未填充完毕的数据继续填充到assist中,//下面两个循环,只会执行其中的一个
        while(p1<=mid)
        {
            assist[i++]=a[p1++];
        }
        while(p2<=hi)
        {
            assist[i++]=a[p2++];
        }
        //到现在为止,assist数组中,从lo到hi的元素是有序的,再把数据拷贝到a数组中对应的索引处
        for (int index=lo;index<=hi;index++)
        {
            a[index]=assist[index];
        }
    }
        /*
        比较v元素是否小于w元素
        */
    private static boolean less(Comparable v, Comparable w) 
    {
        return v.compareTo(w) < 0;
    }
    /*
    数组元素i和j交换位置
    */
    private static void exch(Comparable[] a, int i, int j)
     {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}
//测试代码
public class Test 
{
    public static void main(String[] args) throws Exception 
    {
        Integer[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
        Merge.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

3、堆排序

堆排序原理

1.构造堆;

2.得到堆顶元素,这个值就是最大值;

3.交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;

4.对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;

5.重复2~4这个步骤,直到堆中剩一个元素为止。

堆的构造,最直观的想法就是另外再创建一个和新数组数组,然后从左往右遍历原数组,每得到一个元素后,添加 到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆。 上述的方式虽然很直观,也很简单,但是我们可以用更聪明一点的办法完成它。创建一个新数组,把原数组 0~length-1的数据拷贝到新数组的1~length处,再从新数组长度的一半处开始往1索引处扫描(从右往左),然后 对扫描到的每一个元素做下沉调整即可。

堆排序过程

对构造好的堆,我们只需要做类似于堆的删除操作,就可以完成排序。

1.将堆顶元素和堆中最后一个元素交换位置;

2.通过对堆顶元素下沉调整堆,把最大的元素放到堆顶(此时最后一个元素不参与堆的调整,因为最大的数据已经到 了数组的最右边)

3.重复1~2步骤,直到堆中剩最后一个元素。

 源代码

//堆排序代码
public class HeapSort 
{
    //对source数组中的数据从小到大排序
    public static void sort(Comparable[] source)
    {
        //1.创建一个比原数组大1的数组
        Comparable[] heap = new Comparable[source.length + 1];
        //2.构造堆
        createHeap(source,heap);
        //3.堆排序
        //3.1定义一个变量,记录heap中未排序的所有元素中最大的索引
        int N = heap.length-1;
        while(N!=1)
        {
            //3.2交换heap中索引1处的元素和N处的元素
            exch(heap,1,N);
            N--;
            //3.3对索引1处的元素在0~N范围内做下沉操作
            sink(heap,1,N);
        }
        //4.heap中的数据已经有序,拷贝到source中
        System.arraycopy(heap,1,source,0,source.length);
    }
    //根据原数组source,构造出堆heap
    private static void createHeap(Comparable[] source, Comparable[] heap) 
    {
        //1.把source中的数据拷贝到heap中,从heap的1索引处开始填充
        System.arraycopy(source,0,heap,1,source.length);
        //2.从heap索引的一半处开始倒叙遍历,对得到的每一个元素做下沉操作
        for (int i = (heap.length-1)/2; i>0 ; i--) 
        {
            sink(heap,i,heap.length-1);
        }
    }
    //判断heap堆中索引i处的元素是否小于索引j处的元素
    private static boolean less(Comparable[] heap, int i, int j) 
    {
        return heap[i].compareTo(heap[j])<0;
    }
    //交换heap堆中i索引和j索引处的值
    private static void exch(Comparable[] heap, int i, int j) 
    {
        Comparable tmp = heap[i];
        heap[i] = heap[j];
        heap[j] = tmp;
    }
    //在heap堆中,对target处的元素做下沉,范围是0~range
    private static void sink(Comparable[] heap, int target, int range)
    {
        //没有子结点了
        while (2*target<=range)
        {
            //1.找出target结点的两个子结点中的较大值
            int max=2*target;
            if (2*target+1<=range)
            {
                //存在右子结点
                if (less(heap,2*target,2*target+1))
                {
                    max=2*target+1;
                }
            }
            //2.如果当前结点的值小于子结点中的较大值,则交换
            if(less(heap,target,max))
            {
                exch(heap,target,max);
            }
            //3.更新target的值
            target=max;
        }
    }
}
//测试代码
public class Test 
{
    public static void main(String[] args) throws Exception 
    {
        String[] arr = {"S", "O", "R", "T", "E", "X", "A", "M", "P", "L", "E"};
        HeapSort.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值