❤写在前面
❤博客主页:努力的小鳴人
❤系列专栏:JavaSE超详总结😋
❤欢迎小伙伴们,点赞👍关注🔎收藏🍔一起学习!
❤如有错误的地方,还请小伙伴们指正!🌹🚩在最近的Java学习中,发现Java好多基础知识忘的忘,模糊的模糊,就打算把 【Java】 全部梳理一遍,陆陆续续的文章会放在这里,欢迎订阅一起学习>>>JavaSE超详总结😋
🔥系列传送门:
【03章Java数组】程序员必看数组详解
【02章Java基本语法】详细讲解让你重新认识Java基本语法和流程流程控制
【01章Java语言概述】Java学了很久了吧,快回来熟悉熟悉吧(详细)
文章目录
一、排序算法
- 排序:假设含有n个记录的序列为{R1,R2,…,Rn},其相应的关键字序列为{K1,K2,…,Kn}。将这些记录重新排序为{Ri1,Ri2,…,Rin},使得相应的关键字值满足条Ki1<=Ki2<=…<=Kin,这样的一种操作称为排序。
- 衡量排序算法的优劣:
●时间复杂度
:分析关键字的比较次数和记录的移动次数
●空间复杂度
:分析排序算法中需要多少辅助内存
●稳定性
:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。
👌十大内部排序算法
选择排序
1.直接选择排序
2.堆排序
交换排序
3.冒泡排序
4.快速排序
插入排序
5.直接插入排序
6.折半插入排序
7.Shell排序
8.归并排序
9.桶式排序
10.基数排序
👌直接选择排序
-
排序思想:通常用第一个元素 作为参考值,从第二个元素开始和这个参考值进行比较,比这个参考值大的时候放在这个参考值的后面,比这个参考值小的时候在和这个参考值的前一位进行比较,当比较至适当位置进行插入
-
输入:数组元素数组r,数组r的待排序区间[low,high]
输出:数组r以关键字有序
代码如下:
public void insertSort(Object[] r,int low,int high){
for(int i = low +1;i<=high;i++){ //小于时,需要将r[i]插入有序列表
if(r[i] < r[i-1]){
Object temp = r[i];
r[i] = r[i-1];
int j=i-2;
for(;j>=low&&temp < r[j];j++){
r[j+1] = r[j];//记录后移
}
r[j+1] = temp;//插入到正确位置
}
}
}
👌堆排序
- 定义:是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似
完全二叉树
的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点
。 - 看图思考:
- 排序思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
🎁注:大顶堆:每个结点的值都大于或等于其左右孩子结点的值
小顶堆:每个结点的值都小于或等于其左右孩子结点的值
- 代码如下:
public class HeapSort {
public static void main(String[] args) {
int[] a = {24, 10, 5, 1, 2, 24, 5, 1, 2, 5, 7, 8, 5, 3, 7, 63, 9, 0, 42, 3, 8, 24, 1};
long start = System.currentTimeMillis();
heapSort(a);
System.out.println(Arrays.toString(a));
System.out.println("用时:" + (System.currentTimeMillis() - start));
}
private static void heapSort(int[] a) {
//初始化最大堆,从倒数第二层开始初始化
for (int i = a.length/2; i >=0; i--) {
sortDownHeap(a,a.length,i);
}
//push堆顶元素倒最后,并且重新建立最大堆
for (int i = a.length-1; i >=0 ; i--) {
swap(a,0,i);
sortDownHeap(a,i-1,0);
}
}
//最大堆向下调整
private static void DownHeap(int[] a, int length, int i) {
int t = i+1;
while (2*t <= length) {
int tmpMax = t;// 记录父子节点中的最大下标
if (a[t - 1] < a[2 * t - 1]) {
tmpMax = 2 * t;
}
if (a[tmpMax - 1] < a[2 * t]) {
tmpMax = 2 * t + 1;
}
if (tmpMax != t) { // 如果当前根节点不是最大值
swap(a, t - 1, tmpMax - 1);
t = tmpMax;// 继续向下调整
} else {
return;// 停止调整
}
}
}
private static void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
👌冒泡排序
- 咱们先来看图:
- 冒泡排序思想:
●比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
●对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
●针对所有的元素重复以上的步骤,除了最后一个。
●持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止。 - 代码如下:
public class Test {
public static void main(String[] args) {
int[] array = { 6, 1, 4, 3, 8, 6, 4, 9, 7 };
int len = array.length;
System.out.println("排序前的数组为:"+Arrays.toString(array));
int temp = 0;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (array[j] > array[j + 1]) {
temp = array[j + 1];
array[j + 1] = array[j];
array[j] = temp;
}
}
}
System.out.println("排序后的数组为:"+Arrays.toString(array));
}
}
👌快速排序
快速排序(Quick Sort)由图灵奖获得者Tony Hoare发明,被列为20世纪十大算法之一,是迄今为止所有内排序算法中速度最快的一种。冒泡排序的升级版
,交换排序的一种。
- 快速排序的时间复杂度为O(nlog(n))。
- 思想:
●从数列中挑出一个元素,称为基准
●重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置
●递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
●递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代中,它至少会把一个元素摆到它最后的位置去。 - 时间复杂度
平均时间复杂度为O(N*logN)数组无序时表现较为好
最坏时间复杂度为O(N^2)数组有序且为逆序的时候最坏
👌直接插入排序
- 思想:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表
简单的说:在一组无序的数组中一个个地取出值,将其放在有序的数组中合适的位置,使有序的数组再次有序,直到无序的数组为空,循环结束 - 代码如下:
public class InsertSort{
public static void insSort(int[] a){
for(int i=0; i<a.length; i++){
int tmp = a[i];
int j = 0;
//将第i个值插入当前i-1中的合适位置
for(j=i; j>0&&tmp<a[j-1]; j--){
//从后向前遍历,如果tmp值更小,说明它的位置需要更靠前
//所以依次向后移动一个位置
a[j] = a[j-1];
}
a[j] = tmp;
}
}
public static void main(String args[]){
int[] test = {5,9,4,1,2};
insSort(test);
for(int i=0; i<test.length; i++){
System.out.print(test[i] + " ");
}
}
}
👌折半插入排序
- 排序思想
●1 将第一个元素当做一个查找区的元素,刚开始这个查找区仅含ary[0](第一个元素)
●2 取出下一个元素(这里循环获取,从第二个元素开始),和查找区的中间元素(半查法)比较。注:查找区里面的元素都排好序了
●3 如果新的元素小于中间元素,将查找区的右边界(right变量表示)向左移动一位,如果大于等于中间元素,将左边界(left变量表示)左移一位
●4 重复步骤3,直到左边界大于右边界
●5 判断左边界是否在查找区里面,如果是就从找到的索引位置开始,到该比较元素索引位置结束,向后移动一位。如果在右边界外面,则忽略这一步
●6 将找到的位置元素用比较的元素(第二步取出的数据)覆盖
●7 重复第二步 - 举例代码如下:
public void binaryInsertSort(int[] arr) {
// 将数组第0位作为有序序列,从第1位开始逐一进行插入
for (int i = 1; i < arr.length; i++) {
int temp = arr[i];
int low = 0;
int high = i - 1;
// 使用折半查找法查找要插入的位置
while (low <= high) {
int mid = (low + high) / 2;
if (temp < arr[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
// 向后移位
for (int j = i - 1; j >= mid; j--) {
a[j+1] = a[j];
}
arr[mid] = temp;// 插入元素
}
}
👌Shell排序
- 思想:现将整个待排元素序列分割成若干个子序列分别进行直接插入排序待整个序列中的元素基本有序时,再对全体元素进行一次直接插入排序
👌归并排序
- 思想:先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起
👌桶式排序
仅支持非负数排序
- 需要待排序的序列满足以下两个特征:
●待排序列所有的值处于一个可枚举的范围之内
●待排序列所在的这个可枚举的范围不应该太大,不然排序效率太低 - 步骤如下:
●对于这个可枚举范围构建一个buckets数组,用于记录“落入”每个桶中元素的个数;
●将(1)中得到的buckets数组重新进行计算,按如下公式重新计算:
buckets[i] = buckets[i] +buckets[i-1] (其中1<=i<buckets.length);
👌基数排序
👌算法的五大特征
🎁总结:数组中的十大内部排序算法在平时的应用也算广泛,在这整理下,以后学习方便
👌 作者算是一名Java初学者,文章如有错误,欢迎评论私信指正,一起学习~~
😊如果文章对小伙伴们来说有用的话,点赞👍关注🔎收藏🍔就是我的最大动力!
🚩不积跬步,无以至千里,书接下回,欢迎再见🌹