代码实现在下面
- 冒泡排序 :
1.1 依次遍历比较相邻两个因素的大小
1.2 如果第一个元素大于第二个元素 则调换两个因素的位置 - 插入排序 :
2.1 将数组分为两个区间(已排序/未排序区间)
2.2 默认数组第一个元素为已排序
2.3 拿未排序区间的元素和已排序区间元素倒叙依次比较
2.4 如果未排序区间的元素小于已排序元素 则调换两个元素的位置 - 选择排序 :
3.1 将数组分为两个区间(已排序/未排序区间)
3.2 遍历未排序区间元素
3.3 查找到最小的一个元素 放到已排序区间元素末尾 - 归并排序 :
4.1 使用递归思想将数组切分为两数组直到数组为一个元素为止
4.2 分别对两个数组排序并合并为一个数组
4.3 编码思路 :
a. 创建一个新数组 长度为两个数组长度之和
b. 定义两个指针 分别指向两个数组的第一个元素
c. 依次比较两个指针指向的元素大小 把小的元素放到新数组里 同时元素小的哪个数组指针指向下一个元素
d. 当其中一个数组为空时 直接把另外一个数组元素放到新数组里即可 - 快速排序 :
5.1 定义一个分区点
5.2 遍历数组元素 把元素小的放到分区点左边 大的放到分区点右边
5.3 此时分区点左边元素全部小于分区点元素 右边元素全部大于分区间元素 即分区点为已排序状态
5.4 通过递归使用同样的方法分别处理左右两个区域
5.5 编码思路 :
a. 取出一个分区点元素
b. 定义一个指针指向分区点下标
c. 遍历数组 数组元素小于分区点元素时 把该元素和指针指向的元素调换位置 同时指针指向下一个位置 依次执行
d. 通过递归使用同样的方法分别处理左右两个区域
e. 当数组遍历结束后 把分区点元素和指针指向的元素掉换位置 此时分区点左边元素全部小于分区点元素 分区点右边元素全部大于分区点元素 - 桶排序 :
6.1 创建出桶 (取多少个桶 有多种方法) 桶的取值大小<最后一个桶取最大值> 区间跨度(大小) = (最大值-最小值)/ (桶的数量 - 1)
6.2 遍历所有元素 把元素按照区间放到对应的桶里
6.3 对每个桶进行排序(这里可以自己使用其他排序方法)
6.4 输出全部桶的数据 即排序完成
6.5 编码思路 :
a. 获取最大最小值
b. 创建桶
c. 遍历数组元素放到对应桶里 <按照比例定位元素属于第几个桶 (array[i] - min) * (length-1) / diff>
d. 对每个桶进行排序
e. 输出全部桶的数据 - 计数排序 :
7.1 就是把数组元素作为数组的下标,然后用一个临时数组统计该元素出现的次数
7.2 例如 temp[i] = m, 表示元素 i 一共出现了 m 次。
7.3 最后再把临时数组统计的数据从小到大汇总起来,此时汇总起来是数据是有序的。
7.4 编码思路 :
a. 获取数组最大最小值 <新数组长度为 : 最大值 - 最小值 + 1>
b. 创建新数组 并 统计原数组中所有元素对应个数为多少 <注意 : 新数组下标并非单纯的下标值>
c. 统计数组做变形,后面的元素等于前面的元素之和<排序完成后数组下标 = 新数组元素值 - 1>
d. 创建一个临时数组 存放排序完成后的元素
e. 如果其中相同的元素有多个 则在以新数组中的元素值为下标的元素赋值后 该元素值-1 在下一次在遇到相同的元素时 会自动排到他前面
@SpringBootTest
public class AlgorithmSortTest {
/**
* TODO : 递归 : 阶乘 自己调用自己
* 1. 需要有出口 结束递归
* 2. 执行结构相同
*/
@Test
void test1() {
System.out.println(fun(5));//120
}
int fun(int n) {
if (n == 1) {
return 1;
}
return n * fun(n - 1);
}
/**
* TODO : 排序 : 冒泡
* 1. 比较相邻两个元素的大小 如果第一个大于第二个 就调换两个元素位置 否则不变
* 2. 依次对每对相邻元素执行同样的步骤
*/
@Test
void test2() {
int[] array = {7, 8, 5, 4, 2, 9, 6, 7};
for (int i = 0; i < array.length; i++) {
boolean flag = true;
for (int j = 0; j < array.length - 1; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag = false;//其中只要进来一次 说明没有排序完成 否则说明排序完成 则可以中断循环
}
}
if (flag) {
break;//当循环在执行到一半时 已经排序完成 则跳出循环 一定程度上加快了效率
}
}
System.out.println(Arrays.toString(array));//[2, 4, 5, 6, 7, 7, 8, 9]
}
/**
* TODO : 排序 : 插入
* 1. 数组分为已排序和未排序区间
* 2. 默认第一个元素在已排序区间
* 3. 取出未排序区间所有元素添加到已排序区间 同时保证已排序区间的有序性 直到未排序区间为空 则排序完成
*/
@Test
void test3() {
int[] array = {7, 8, 5, 4, 2, 9, 6, 7};
for (int i = 1; i < array.length; i++) {
//获取当前要排序的元素
int current = array[i];
//拿当前元素和已排序区间元素倒叙依次比较
for (int j = i; j > 0 && current < array[j - 1]; j--) {
//如果当前元素小于已排序元素 则向前移动
int temp = array[j - 1];
array[j - 1] = array[j];
array[j] = temp;
}
}
System.out.println(Arrays.toString(array));//[2, 4, 5, 6, 7, 7, 8, 9]
}
/**
* TODO : 排序 : 选择
* 1. 分为已排序和未排序区间 已排序区间为空
* 2. 查找未排序区间最小值 放到已排序区间的末尾 直到未排序区间为空
*/
@Test
void test4() {
int[] array = {7, 8, 5, 4, 2, 9, 6, 7};
for (int i = 0; i < array.length; i++) {
//未排序区间的最小值下标
int minIndex = i;
for (int j = i; j < array.length; j++) {
if (array[j] < array[minIndex]) {
minIndex = j;
}
}
int current = array[i];
array[i] = array[minIndex];
array[minIndex] = current;
}
System.out.println(Arrays.toString(array));//[2, 4, 5, 6, 7, 7, 8, 9]
}
/**
* TODO : 排序 : 归并 : 使用到了递归实现
* 1. 把数组拆分<直到分为每个数组一个元素位置> 然后分别排序 排序结束后在合并两部分即可排序完成
*/
@Test
void test5() {
int[] array = {7, 8, 5, 4, 2, 9, 6, 7, 1};
int[] mergerArr = mergeSort(array);
System.out.println(Arrays.toString(mergerArr));
}
//拆分数组
int[] mergeSort(int[] array) {
if (array.length < 2) {
return array;
}
//拆分数组
int mid = array.length / 2;
int[] left = Arrays.copyOfRange(array, 0, mid);
int[] right = Arrays.copyOfRange(array, mid, array.length);
return merge(mergeSort(left), mergeSort(right));//递归拆分排序
}
//进行排序
int[] merge(int[] left, int[] right) {
//合并数组
//创建一个新数组 长度为传入数组长度之和
int[] newArr = new int[left.length + right.length];
/*
1. 定义2个指针 分别指向左右两个数组的下标
2. 比较left和right数组指针所对应的元素 小的就放到新数组里 元素小的哪个数组指针移向下一位
3. 重复第二步 直到比较完成 如果一个数组元素已经全部放到新数组 另外一个数组则不需要继续比较直接放到新数组即可<已经是有序的>
4. https://blog.csdn.net/bjweimengshu/article/details/102384930?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160386623319724836758350%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=160386623319724836758350&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-2-102384930.pc_search_result_cache&utm_term=%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F&spm=1018.2118.3001.4187
*/
int pointerLeft = 0;
int pointerRigh = 0;
for (int i = 0; i < newArr.length; i++) {
if (pointerLeft >= left.length) {//当左边数组长度为0时 则把右边数组元素全部放到新数组里
newArr[i] = right[pointerRigh++];
} else if (pointerRigh >= right.length) {//当右边数组长度为0时 则把左边数组元素全部放到新数组里
newArr[i] = left[pointerLeft++];
} else if (left[pointerLeft] < right[pointerRigh]) {//左边数组元素小于右边数组元素 则把左边数组元素放到新数组
newArr[i] = left[pointerLeft++];
} else {//否则把右边数组元素放到新数组里
newArr[i] = right[pointerRigh++];
}
}
return newArr;
}
/**
* TODO : 排序 : 快速 : 使用到了递归实现
* 1. 选择数组里任意元素作为分区点
* 2. 遍历数组 将小于分区点的元素放到左边 大于分区点的元素放到分区点右边
* 3. 此时分区点左边都小于该元素 右边大于或等于该元素 则该分区点处于有序状态 且把数组分为只有两个区域
* 4. 通过递归的使用同样的方法分别处理左右两个区域 递归的终结点就是当数组长度为一的时候
* 5. https://mp.weixin.qq.com/s?__biz=Mzg2NzA4MTkxNQ==&mid=2247485191&idx=1&sn=45a43bd77495566db53b419ae82136f5&source=41#wechat_redirect
*/
@Test
void test6() {
int[] array = {7, 8, 5, 4, 2, 9, 6, 7, 1};
quickSort(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
void quickSort(int[] array, int begin, int end) {
//终结条件
if (array.length <= 1 || begin >= end) {
return;
}
int partition = partition(array, begin, end);
quickSort(array, begin, partition - 1);
quickSort(array, partition + 1, end);
}
//获取分区点
int partition(int[] array, int begin, int end) {
//默认分区点为待分区的最后一位数 可以自己定义
int point = array[end];
//定义分区下标指针 当找到小于分区点的元素 则和该下标元素替换位置 且下标位置指向下一位
int pointIndex = begin;
for (int i = begin; i < end; i++) {
//如果数组里有小于分区点的元素 则将该元素从区间第一个元素开始向后填充
if (array[i] < point) {
//元素下标大于分区下标时 进行替换 小于时 该元素就在分区点下标左边 不需要替换
if (i > pointIndex) {
int temp = array[pointIndex];
array[pointIndex] = array[i];
array[i] = temp;
}
pointIndex++;
}
}
/*
1. 当遍历完成后 小于分区点的元素已经全部放到了左边
2. 然后把分区点元素和pointIndex下标的元素替换位置
3. 此时分区点位置左边都元素全部小于分区点元素 右边元素全部大于分区点元素
*/
int temp = array[end];
array[end] = array[pointIndex];
array[pointIndex] = temp;
return pointIndex;
}
/**
* TODO : 排序 : 桶排序
* 1. 创建桶 确定桶的区间范围 <具体创建多少桶 有多种方法>
* 2. 这里我们可以创建和原始数组长度相同的桶 最后一个桶取最大值 前面桶取值范围按照如下比例 区间跨度(大小) = (最大值-最小值)/ (桶的数量 - 1)
* 3. 遍历数组 把元素按照桶区间放到各个桶里
* 4. 对每个桶分别排序
* 5. 遍历所有桶输出所有元素 排序完成
*/
@Test
void test7() {
double[] array = {3.0, 1.5, 5.0, 6.9, 8.8, 9.0, 1.6};
if (array.length <= 0) {
return;
}
//1. 得到数组最大最小值
double min = array[0];
double max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
if (array[i] < min) {
min = array[i];
}
}
//计算差值
double diff = max - min;
//2. 创建桶 所有桶保存在集合里 每个桶定义为链表 方便在插入数据到尾部
int length = array.length;//桶的长度
ArrayList<LinkedList<Double>> barrelList = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
barrelList.add(new LinkedList<Double>());
}
//3. 遍历数组 将每个元素插入到桶里 按照比例定位元素属于第几个桶 (array[i] - min) * (length-1) / diff
for (int i = 0; i < array.length; i++) {
int n = (int) ((array[i] - min) * (length - 1) / diff);
LinkedList<Double> linkedList = barrelList.get(n);
linkedList.add(array[i]);
}
//4. 对每个非空桶内元素进行排序
for (int i = 0; i < barrelList.size(); i++) {
LinkedList<Double> linkedList = barrelList.get(i);
if (linkedList.size() != 0 && linkedList != null) {
Collections.sort(linkedList);//使用jdk自带排序算法
}
}
//5. 输出全部桶的数据
double[] doubles = new double[length];
int index = 0;
for (LinkedList<Double> doubleLinkedList : barrelList) {
for (Double element : doubleLinkedList) {
doubles[index] = element;
index++;
}
}
System.out.println(Arrays.toString(doubles));
}
/**
* TODO : 排序 : 计数
* 1. 就是把数组元素作为数组的下标,然后用一个临时数组统计该元素出现的次数
* 2. 例如 temp[i] = m, 表示元素 i 一共出现了 m 次。
* 3. 最后再把临时数组统计的数据从小到大汇总起来,此时汇总起来是数据是有序的。
*/
@Test
void test8() {
int[] array = {90, 95, 91, 98, 99, 99, 96, 97, 97, 92};
//创建一个数组长度为 最大值 - 最小值 + 1
int min = array[0];
int max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
if (array[i] < min) {
min = array[i];
}
}
//数组长度为 最大值 - 最小值 + 1
int length = max - min + 1;
//创建统计数组
int[] arr = new int[length];
//统计对应元素的个数
for (int i = 0; i < array.length; i++) {
//原数组元素 - 最小值 就是新数组元素的下标
arr[array[i] - min] += 1;//取出新的数组元素 +1 在赋值给该元素 记录了该元素个数+1
}
//统计数组做变形,后面的元素等于前面的元素之和
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
arr[i] = sum;
}
//创建临时数组 存储最终有序列表
int[] tempSort = new int[array.length];
for (int i = array.length - 1; i >= 0; i--) {
//arr[array[i] - min] - 1 : 获取元素排序后的下标<因为索引从0开始 所以 -1>
tempSort[arr[array[i] - min] - 1] = array[i];
/*
1. 如果有重复元素 我们需要把对应的计量临时数组下标的元素值-1
2. 否则重复元素会覆盖上一个元素
例如 这里array[]有2个99元素和97元素
如果没有改变其下标位置
则输出会如下 [90, 91, 92, 95, 96, 0, 97, 98, 0, 99]
正常输出应该是 [90, 91, 92, 95, 96, 97, 97, 98, 99, 99]
*/
arr[array[i] - min]--;
}
System.out.println(Arrays.toString(tempSort));
}
}