十大排序算法(java实现)

注:本篇仅用来自己学习,大量内容来自菜鸟教程(地址:1.0 十大经典排序算法 | 菜鸟教程)

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。【冒泡、插入、选择、快速、归并排序面试中出现概率极高】

1.冒泡排序

冒泡排序(Bubble Sort) 是一种简单直观的排序。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

算法步骤:

  • 比较相邻的元素,如果第一个比第二个大,就交换他们两个。

  • 对每一对相邻元素进行同样工作,直到最后的元素是最大的数。

  • 重复上述工作,直到数字是有序的。

实现代码:

public class BubbleSort implements IArraySort {
​@Overridepublic int[] sort(int[] sourceArray) throws Exception {// 对 arr 进行拷贝,不改变参数内容int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
​for (int i = 1; i < arr.length; i++) {// 设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已经完成。boolean flag = true;
​for (int j = 0; j < arr.length - i; j++) {if (arr[j] > arr[j + 1]) {int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;
​flag = false;}}
​if (flag) {break;}}return arr;}
}

2.选择排序

选择排序是一种简单直观的排序算法,其基本思想是每次从待排序的元素中选择最小(或最大)的元素,放置到已排序序列的末尾(或开头),直到所有元素都排序完成为止。

算法步骤:

  • 在未排序的序列中找出最小(大)元素,存放在排序序列的起始位置。

  • 接着从剩余未排序的序列中继续寻找最小(大)元素,然后放到已排序序列的末尾。

  • 重复上述步骤,直到所有元素均排序完毕。

实现代码:

public class SelectionSort implements IArraySort {
​@Overridepublic int[] sort(int[] sourceArray) throws Exception {int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
​// 总共要经过 N-1 轮比较for (int i = 0; i < arr.length - 1; i++) {int min = i;
​// 每轮需要比较的次数 N-ifor (int j = i + 1; j < arr.length; j++) {if (arr[j] < arr[min]) {// 记录目前能找到的最小值元素的下标min = j;}}
​// 将找到的最小值和i位置所在的值进行交换if (i != min) {int tmp = arr[i];arr[i] = arr[min];arr[min] = tmp;}
​}return arr;}
}

3.插入排序

插入排序是一种简单直观的排序算法,其基本思想是将待排序的元素逐个插入到已经排序的序列中的合适位置,直到整个序列都排好序为止。

算法步骤:

  • 将第一个元素视为已排序序列,其余元素为待排序序列。

  • 从第二个元素开始,逐个将待排序序列中的元素插入到已排序序列中的合适位置。

  • 对于每一个待排序元素,从其前一个元素开始,依次向前比较,直到找到合适的插入位置。

  • 插入元素后,已排序序列长度加一,待排序序列长度减一。

  • 重复以上步骤,直到所有元素都被插入到已排序序列中,排序完成。

代码实现:

public class InsertSort implements IArraySort {
​@Overridepublic int[] sort(int[] sourceArray) throws Exception {// 对 arr 进行拷贝,不改变参数内容int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
​// 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的for (int i = 1; i < arr.length; i++) {
​// 记录要插入的数据int tmp = arr[i];
​// 从已经排序的序列最右边的开始比较,找到比其小的数int j = i;while (j > 0 && tmp < arr[j - 1]) {arr[j] = arr[j - 1];j--;}
​// 存在比其小的数,插入if (j != i) {arr[j] = tmp;}
​}return arr;}
}

4.希尔排序

希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。

算法步骤:

  • 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;

  • 按增量序列个数 k,对序列进行 k 趟排序;

  • 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

代码实现:

public static void shellSort(int[] arr) {int length = arr.length;int temp;for (int step = length / 2; step >= 1; step /= 2) {for (int i = step; i < length; i++) {temp = arr[i];int j = i - step;while (j >= 0 && arr[j] > temp) {arr[j + step] = arr[j];j -= step;}arr[j + step] = temp;}}
}

5.归并排序

归并排序是一种分治算法,它将一个待排序的序列分成两个子序列,分别对两个子序列进行排序,然后将两个已排序的子序列合并成一个有序序列。

算法步骤:

  1. 分解:将待排序的序列分解为两个子序列,直到每个子序列只包含一个元素。

  2. 解决:递归地对每个子序列进行排序。

  3. 合并:将两个已排序的子序列合并成一个有序序列。

代码实现:

public class MergeSort {// 归并排序算法public static void mergeSort(int[] arr, int left, int right) {if (left < right) {int mid = (left + right) / 2;// 分解成两个子序列并递归排序mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);// 合并已排序的两个子序列merge(arr, left, mid, right);}}
​// 合并两个已排序的子序列public static void merge(int[] arr, int left, int mid, int right) {// 计算左右子序列的长度int n1 = mid - left + 1;int n2 = right - mid;
​// 创建临时数组存储左右子序列的元素int[] L = new int[n1];int[] R = new int[n2];
​// 将元素复制到临时数组中for (int i = 0; i < n1; i++) {L[i] = arr[left + i];}for (int j = 0; j < n2; j++) {R[j] = arr[mid + 1 + j];}
​// 合并两个子序列int i = 0, j = 0, k = left;while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k] = L[i];i++;} else {arr[k] = R[j];j++;}k++;}
​// 将左子序列剩余的元素复制到原始数组中while (i < n1) {arr[k] = L[i];i++;k++;}
​// 将右子序列剩余的元素复制到原始数组中while (j < n2) {arr[k] = R[j];j++;k++;}}
}

6.快速排序

快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

算法步骤:

  • 从数列中挑出一个元素,称为 "基准"(pivot)。

  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

代码实现:

public class QuickSort implements IArraySort {
​@Overridepublic int[] sort(int[] sourceArray) throws Exception {// 对 arr 进行拷贝,不改变参数内容int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
​return quickSort(arr, 0, arr.length - 1);}
​private int[] quickSort(int[] arr, int left, int right) {if (left < right) {int partitionIndex = partition(arr, left, right);quickSort(arr, left, partitionIndex - 1);quickSort(arr, partitionIndex + 1, right);}return arr;}
​private int partition(int[] arr, int left, int right) {// 设定基准值(pivot)int pivot = left;int index = pivot + 1;for (int i = index; i <= right; i++) {if (arr[i] < arr[pivot]) {swap(arr, i, index);index++;}}swap(arr, pivot, index - 1);return index - 1;}
​private void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
​
}

7.堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列。

算法步骤:

  • 创建一个堆 H[0……n-1]。

  • 把堆首(最大值)和堆尾互换。

  • 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置。

  • 重复步骤 2,直到堆的尺寸为 1。

代码实现:

public class HeapSort implements IArraySort {
​@Overridepublic int[] sort(int[] sourceArray) throws Exception {// 对 arr 进行拷贝,不改变参数内容int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
​int len = arr.length;
​buildMaxHeap(arr, len);
​for (int i = len - 1; i > 0; i--) {swap(arr, 0, i);len--;heapify(arr, 0, len);}return arr;}
​private void buildMaxHeap(int[] arr, int len) {for (int i = (int) Math.floor(len / 2); i >= 0; i--) {heapify(arr, i, len);}}
​private void heapify(int[] arr, int i, int len) {int left = 2 * i + 1;int right = 2 * i + 2;int largest = i;
​if (left < len && arr[left] > arr[largest]) {largest = left;}
​if (right < len && arr[right] > arr[largest]) {largest = right;}
​if (largest != i) {swap(arr, i, largest);heapify(arr, largest, len);}}
​private void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
​
}

8.桶排序

桶排序是一种分布式排序算法。基本思想是将要排序的数据分到有限数量的桶中,每个桶再分别进行排序(可以使用其他排序算法,如插入排序、快速排序等),最后将各个桶中的数据按顺序合并起来,得到最终的排序结果。

示意图:

代码实现:

public class BucketSort implements IArraySort {
​private static final InsertSort insertSort = new InsertSort();
​@Overridepublic int[] sort(int[] sourceArray) throws Exception {// 对 arr 进行拷贝,不改变参数内容int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
​return bucketSort(arr, 5);}
​private int[] bucketSort(int[] arr, int bucketSize) throws Exception {if (arr.length == 0) {return arr;}
​int minValue = arr[0];int maxValue = arr[0];for (int value : arr) {if (value < minValue) {minValue = value;} else if (value > maxValue) {maxValue = value;}}
​int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1;int[][] buckets = new int[bucketCount][0];
​// 利用映射函数将数据分配到各个桶中for (int i = 0; i < arr.length; i++) {int index = (int) Math.floor((arr[i] - minValue) / bucketSize);buckets[index] = arrAppend(buckets[index], arr[i]);}
​int arrIndex = 0;for (int[] bucket : buckets) {if (bucket.length <= 0) {continue;}// 对每个桶进行排序,这里使用了插入排序bucket = insertSort.sort(bucket);for (int value : bucket) {arr[arrIndex++] = value;}}
​return arr;}
​/*** 自动扩容,并保存数据** @param arr* @param value*/private int[] arrAppend(int[] arr, int value) {arr = Arrays.copyOf(arr, arr.length + 1);arr[arr.length - 1] = value;return arr;}
​
}

9.基数排序

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

示意图:

代码:

/*** 基数排序* 考虑负数的情况还可以参考: https://code.i-harness.com/zh-CN/q/e98fa9*/
public class RadixSort implements IArraySort {
​@Overridepublic int[] sort(int[] sourceArray) throws Exception {// 对 arr 进行拷贝,不改变参数内容int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
​int maxDigit = getMaxDigit(arr);return radixSort(arr, maxDigit);}
​/*** 获取最高位数*/private int getMaxDigit(int[] arr) {int maxValue = getMaxValue(arr);return getNumLenght(maxValue);}
​private int getMaxValue(int[] arr) {int maxValue = arr[0];for (int value : arr) {if (maxValue < value) {maxValue = value;}}return maxValue;}
​protected int getNumLenght(long num) {if (num == 0) {return 1;}int lenght = 0;for (long temp = num; temp != 0; temp /= 10) {lenght++;}return lenght;}
​private int[] radixSort(int[] arr, int maxDigit) {int mod = 10;int dev = 1;
​for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {// 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10)int[][] counter = new int[mod * 2][0];
​for (int j = 0; j < arr.length; j++) {int bucket = ((arr[j] % mod) / dev) + mod;counter[bucket] = arrayAppend(counter[bucket], arr[j]);}
​int pos = 0;for (int[] bucket : counter) {for (int value : bucket) {arr[pos++] = value;}}}
​return arr;}
​/*** 自动扩容,并保存数据** @param arr* @param value*/private int[] arrayAppend(int[] arr, int value) {arr = Arrays.copyOf(arr, arr.length + 1);arr[arr.length - 1] = value;return arr;}
}

10.计数排序

计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

算法步骤:

  • 找出待排序的数组中最大和最小的元素

  • 统计数组中每个值为i的元素出现的次数,存入数组C的第i项

  • 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)

  • 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

代码实现:

public class CountingSort implements IArraySort {
​@Overridepublic int[] sort(int[] sourceArray) throws Exception {// 对 arr 进行拷贝,不改变参数内容int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
​int maxValue = getMaxValue(arr);
​return countingSort(arr, maxValue);}
​private int[] countingSort(int[] arr, int maxValue) {int bucketLen = maxValue + 1;int[] bucket = new int[bucketLen];
​for (int value : arr) {bucket[value]++;}
​int sortedIndex = 0;for (int j = 0; j < bucketLen; j++) {while (bucket[j] > 0) {arr[sortedIndex++] = j;bucket[j]--;}}return arr;}
​private int getMaxValue(int[] arr) {int maxValue = arr[0];for (int value : arr) {if (maxValue < value) {maxValue = value;}}return maxValue;}
​
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/688097.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java——类与对象

目录 一、面向对象的初步认识 1.1 什么是面向对象 1.2 面向对象与面向过程 二、类的定义与使用 2.1 简单认识类 2.2 类的定义格式 三、类的实例化 3.1 什么是实例化 3.2 类和对象的说明 四、this引用 4.1 为什么要有this引用 4.2 什么是this引用 ​编辑 4.3 this引用…

Google console 带包 号

https://play.google.com/store/apps/details?idcom.winmoney.moneyincome 懂的 来tg goomoni

【redis】Redis五种常用数据类型和内部编码,以及对String字符串类型的总结

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

在线教程|图灵奖得主Yann LeCun盛赞!小红书开源InstantID,一张原图即可定制多种风格写真

不久前&#xff0c;一群来自小红书的 95 后工程师联合北大团队发布了开源项目「InstantID」&#xff0c;只需上传一张照片&#xff0c;这款 AI 写真神器就能轻松定制多种风格的 AI 写真&#xff0c;告别繁琐修图。 InstantID 一经发布就引起了广泛关注&#xff0c;GitHub 收藏量…

【LeetCode算法】28. 找出字符串中第一个匹配项的下标

提示&#xff1a;此文章仅作为本人记录日常学习使用&#xff0c;若有存在错误或者不严谨得地方欢迎指正。 文章目录 一、题目二、思路三、解决方案四、JAVA截取字符串的常用方法4.1 通过subString()截取字符串* 一、题目 给你两个字符串 haystack 和 needle &#xff0c;请你在…

如果通过Glide 设置图片圆角

要给图片设置一个圆角,通常方法是在ImageView 标签外添加一个CardView 标签,然后设置圆角值,但是今天遇到一个问题就是 RecyclerView Item 中这样操作的话会遇到这样的一个报错: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.rec…

web前端之sass中的颜色函数、active按钮激活、hover鼠标悬浮、disabled禁用、scss循环、css

MENU 效果图htmlsassscss编译后的css页面css 效果图 注意查看蓝色按钮。 html <div class"box"><button class"btn type_1">按钮</button><button class"btn type_2">按钮</button><button class"btn ty…

「TypeScript」TypeScript入门练手题

前言 TypeScript 越来越火&#xff0c;现在很多前端团队都使用它&#xff0c;因此咱们前端码农要想胜任以后的前端工作&#xff0c;就要更加熟悉它。 入门练手题 interface A {x: number;y: number; }type T Partial<A>;const a: T { x: 0, y: 0 }; const b: T { …

专题六_模拟(3)

目录 1419. 数青蛙 解析 题解 1419. 数青蛙 1419. 数青蛙 - 力扣&#xff08;LeetCode&#xff09; 解析 题解 class Solution { public:int minNumberOfFrogs(string croakOfFrogs) {// 44.专题六_模拟_数青蛙_Cstring t "croak";int n t.size();vector<in…

力扣HOT100 - 215. 数组中第K个最大元素

解题思路&#xff1a; 快速选择&#xff0c;目标是找出数组中第 k 小&#xff08;或第 k 大&#xff09;的元素&#xff0c;而不是对整个数组进行排序。 &#xff08;需要和快排进行区分&#xff0c;快排的目的是排序&#xff09; 注意&#xff1a; i l - 1, j r 1; 为什…

短剧奔向小程序,流量生意如何开启?

随着移动互联网的飞速发展&#xff0c;小程序作为一种轻量级、易传播的应用形态&#xff0c;逐渐在各个领域展现出其独特的商业价值。而最近爆火的短剧小视频作为一种受众广泛的娱乐形式&#xff0c;与小程序结合后&#xff0c;不仅为观众提供了更为便捷的观看体验&#xff0c;…

torch.searchsorted

torch.searchsorted 官方文档链接&#xff1a;torch.searchsorted — PyTorch 2.3 documentation 该函数用于在已排序的序列中查找要插入的值的位置&#xff0c;以保持序列的顺序&#xff0c; torch.searchsorted(sorted_sequence, values, *, out_int32False, rightFalse, s…