数据结构和算法学习笔记——排序

        排序算法的内容会随着博主的学习进度更新,内容介绍了各个算法的原理,并且都有代码示例。

目录

1.Comparable接口介绍

2.冒泡排序

3.选择排序

4.插入排序

※5.希尔排序

※6.归并排序

    6.1递归

    6.2归并排序

※7.快速排序

※8.堆排序


1.Comparable接口介绍

        介绍:在一个需要可以进行比较的类实现Comparable接口,并重写Comparable接口的compareTO方法,以此来提供一个比较规则,从而实现类的比较。代码示例如下:

//Student类
public class Student implements Comparable<Student> {

    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //重写Comparable类中的compareTo方法
    @Override 
    public int compareTo(Student o) {
        return this.age - o.age;
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("张三", 18);
        Student student2 = new Student("李四", 16);
        System.out.println(getMaxAge(student1, student2));
    }

    //实现比较方法
    public static Student getMaxAge(Student o1, Student o2) {
        int n = o1.compareTo(o2);
        if(n >= 0) return o1;
        else  return o2;
    }
}

2.冒泡排序

        原理:比较相邻元素,如果前一个元素比后一个元素大,就交换这两个元素的位置;每一次遍历都对每一对相同元素做同样的,直到最后排序完成。代码示例如下:

package SortDemo;

//冒泡排序实现
public class Bubble {

    //排序
    public static void sort(Comparable[] a) {
        for(int i = a.length - 1; i > 0; i--) {
            for(int j = 0; j < i; j++) {
                if(greater(a[i], a[j]))
                    exchange(a, i, j);
            }
        }
    }

    //比较两个值v和w的大小
    public static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }
    
    //交换数组a中下标为i和j的值
    public static void exchange(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

}
package SortDemo;

import java.util.Arrays;

//冒泡排序测试
public class Test {
    public static void main(String[] args) {
        Integer[] a = {8,4,2,3,6,7,5,1,0};
        Bubble.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

 冒泡排序的时间复杂度是O(n^2),所以它适用于较小量的比较场景。


3.选择排序

        原理:在每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处的值大于其他某个索引处的值,则进行交换,并假定其他某个索引处的值为最小值,但索引未变。示例代码如下:

package SelectionDemo;

public class Selection {

    //排序
    public static void sort(Comparable[] a) {
        for(int i = 0; i < a.length; i++) {
            int minIndex = i;
            for(int j = i + 1; j < a.length; j++) {
                if(greater(a[minIndex], a[j]))
                    minIndex = j;
            }
            exchange(a, i, minIndex);
        }
    }

    //比较两个值v和w的大小
    public static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    //交换数组a中下标为i和j的值
    public static void exchange(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}
package SelectionDemo;

import java.util.Arrays;

//选择排序测试
public class SelectionTest {
        public static void main(String[] args) {
            Integer[] a = {8,4,2,3,6,7,5,1,0};
            Selection.sort(a);
            System.out.println(Arrays.toString(a));
        }
    }

  选择排序的时间复杂度是O(n^2),所以它适用于较小量的比较场景。


4.插入排序

原理:

  1. 形象地把所有的元素分为两组,已排序组和未排序组;
  2. 找到未排序组中的第一个元素,向已排序组中进行插入;
  3. 倒叙遍历已排序组,依次与未排序组的第一个元素进行比较,符合条件进行交换并进行下一次比较,若不符合条件,即已排序没有比未排序组的第一个元素小的,则跳出当前循环并进行未排序组下一个元素的排序。

代码示例如下:

package InsertionDemo;

public class Insertion {

    //排序
    public static void sort(Comparable[] a) {
        for(int i = 1; i < a.length; i++) {
            for(int j = i; j > 0 ; j--) {
                if(greater(a[j - 1], a[j]))
                    exchange(a, j - 1, j);
                else
                    break;
            }
        }
    }

    //比较两个值v和w的大小
    public static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    //交换数组a中下标为i和j的值
    public static void exchange(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}
package InsertionDemo;

import java.util.Arrays;

//插入排序测试
public class InsertionTest {
    public static void main(String[] args) {
        Integer[] a = {8,4,2,3,6,7,5,1,0};
        Insertion.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

   插入排序的时间复杂度是O(n^2),所以它适用于较小量的比较场景。


※5.希尔排序

原理:

  1. 选定一个增长量h,按照增长量h作为数组分组的依据,对数据进行分组;
  2. 对分好组的每一组数据完成插入排序;
  3. 减小增长量,最小减为1,重复第二步。

增长量确定依据:

int h = 1;

//h的增长规律
while(h < 数组长度/2) {
    h =2 * h + 1;
}

//h的减小规律
h = h / 2;

代码示例如下: 

package ShellDemo;

//希尔排序实现
public class Shell {

    public static void sort(Comparable[] a) {
        int h = 1;
        while(h < a.length) {
            h = 2 * h + 1;
        }
        //当增长量h=1时,排序结束
        while(h >= 1) {
            //找到待排序的元素
            for(int i = h; i < a.length; i++) {
                //将待排序元素插入已排序组中
                for(int j = i; j >= h; j -= h) {
                    if(greater(a[j], a[j - h]))
                        exchange(a, j, j - h);
                    else
                        break;
                }
            }
            h = h / 2;
        }
    }

    //比较两个值v和w的大小
    public static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    //交换数组a中下标为i和j的值
    public static void exchange(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}
package ShellDemo;

import java.util.Arrays;

//希尔排序测试
public class ShellTest {
    public static void main(String[] args) {
        Integer[] a = {8,4,2,3,6,7,5,1,0};
        Shell.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

        在进行大量数据排序时,希尔排序所用时间是冒泡、选择和插入排序的千分之一,所以希尔排序适合进行大量数据排序的场景。


※6.归并排序

    6.1递归

        定义:在定义方法时,在方法的内部调用方法的本身,称之为递归。

public void show() {
    System.out.println("aaa");
    show();
}
//这样写实际上有些错误,没有结束条件,会进入死循环

         实际应用代码示例如下:

//求n的阶乘
public class FactorialTest {
    public static void main(String[] args) {
        System.out.println(factorial(5));   //120
    }

    public static long factorial(int n) {
        if(n == 1)
            return 1;
        else
            return n * factorial(n - 1);
    }
}

    6.2归并排序

        原理:通过递归,将原数组从中间分为两组,直至分到不能分为止,然后对分组后的数组进行排序,再将排序后的数组归并到原数组,完成排序。代码示例如下:

package MergeDemo;

public class Merge {

    //辅助数组
    static Comparable[] assist;

    //对数组a进行排序
    public static void sort(Comparable[] a) {
        //初始化辅助数组
        assist = new Comparable[a.length];
        //定义lo记录数组最小索引,定义hi记录数组最大索引
        int lo = 0;
        int hi = a.length - 1;
        //对数组a中从索引lo到索引hi的元素排序
        sort(a, lo, hi);
    }

    //对数组a中从索引lo到索引hi的元素排序
    public static void  sort(Comparable[] a, int lo, int hi) {
        if(hi <= lo)
            return;
        //对数组进行分组
        int mid = lo + (hi - lo) / 2;
        //对分组后的数组元素进行排序
        sort(a, lo, mid);   //对索引lo到索引mid的元素排序
        sort(a, mid + 1, hi);   //对索引mid+1到索引hi的元素排序
        //将排完序的两个数组归并
        merge(a, lo, mid, hi);
    }

    private static void merge(Comparable[] a, int lo, int mid, int hi) {
        //定义三个指针
        int i = lo ;
        int p1 = lo;
        int p2 = mid + 1;
        //对两组数据的元素进行比较,并存入辅助数组
        while(lo <= mid && p2 <= hi) {
            if(greater(a[p1], a[p2]))
                assist[i++] = a[p1++];
            else
                assist[i++] = a[p2++];
        }
        //如果指针p1没有走完,那么顺序移动p1指针,把对应元素放到辅助数组的对应索引处
        while(p1 <= mid)
            assist[i++] = a[p1++];
        //如果指针p2没有走完,那么顺序移动p2指针,把对应元素放到辅助数组的对应索引处
        while(p2 <= hi)
            assist[i++] = a[p2++];
        //将辅助数组中的数据拷贝到原数组中
        for(int index = lo; index <= hi; index++)
            a[index] = assist[index];
    }

    //比较两个值v和w的大小
    public static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    //交换数组a中下标为i和j的值
    public static void exchange(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

}
package MergeDemo;

import java.util.Arrays;

//归并排序测试
public class MergeTest {
    public static void main(String[] args) {
        Integer[] a = {8,4,2,3,6,7,5,1,0};
        Merge.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

归并排序的时间复杂度减小到了O(logn),适合于对大量数据进行排列的场合。

视频教程:黑马程序员Java数据结构与java算法,全网资料最全数据结构+算法教程,154张java数据结构图_哔哩哔哩_bilibili


※7.快速排序

    原理:

  1. 设置一个分界值,通过该分界值将数组分成左右两部分;
  2. 将大于或等于分界值的放在分界值右边,小于分界值的放在左边;
  3. 分别对分界值两边的数组重复上述过程;(可以看出这是一个递归)
  4. 再通过递归分别对左右两个数组进行排序,当递归结束,整个数组就排好了。

代码示例如下:

视频教程:黑马程序员Java数据结构与java算法,全网资料最全数据结构+算法教程,154张java数据结构图_哔哩哔哩_bilibili


※8.堆排序

        待补充

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值