前言

为了准备面试,从2月开始将排序算法认认真真得刷了一遍,通过看书看视频,实践打代码,还有一部分的leetcode题,自己感觉也有点进步,将笔记记录总结发出来。

冒泡排序

  • 该排序就是一种像泡泡浮到水面以后,将其挑选,这种浮出来的前提是就是或者是小的/大的先露头,将/小的大的检索出来。(根据从大到小或者反过来)
package src.datastructure;

import java.util.Arrays;

/**
* @Author: yhy
* @Time: 23:49
*/
//时间复杂度O(n^2)
public class DubbleSort {
public static void main(String[] args) {
int[] abc = {1,9,-2,40,33};
int temp = 0;
boolean flag = false;
//第一轮for,n个数都要参与比较。
for (int i = 0; i <abc.length-1 ; i++) {
//第1个和其他的数进行比较。。再到第二个数与其他的
for (int j = 0; j < abc.length-1 ; j++) {
//这里是升序排序
if (abc[j] > abc[j+1]) {
flag = true;
temp = abc[j];
abc[j] = abc[j+1];
abc[j+1] = temp;
} }
//这里优化了一些,减少了比较的次数,若排好序了,就直接跳出循环,输出结果
if (!flag) {
break;
}else {
flag = false;
} }
System.out.println(Arrays.toString(abc)); } }

选择排序

  • 先找个值假设作为最小值,进行该值以后的数与该值比较,小的就放在前面
package src.datastructure;

import java.util.Arrays;

/**
* @Author: yhy
* @Time: 15:30
* 选择排序
*/
public class SelectSort {
public static void main(String[] args) {
int[] abc = {1,9,-2,40,33};
// 选择排序:选择一开始为最小的,然后每一次开始排序
// 也有最小值还有最小值的索引
for (int i = 0; i < abc.length; i++) {
int min = abc[i];
int minIndex = i;
for (int j = i+1; j < abc.length; j++) {
if (min > abc[j]) {
min = abc[j];
minIndex = j;
abc[j] = abc[i];
}
// 关键判断;要将原来的索引与min比较,若发生了交换,就将相对小的数放在前面去
if (minIndex != i) {
abc[i] = min; }
} }
System.out.println(Arrays.toString(abc)); } }

插入排序

  • 插入意思就是从无序区找值插到有序区去,所以取第一个值为有序区,等到有序区长度为n(数组长度)时候就成功排序。
package src.datastructure;

import java.util.Arrays;

/**
* @Author: yhy
* @Time: 15:30
*/
public class InsertSort {
public static void main(String[] args) {
int[] abc = {1,9,-2,40,33};
// 插入排序,分为有序区,和无序区
// 和选择排序有那么一点相似,
// 这里是将一部分定义为有,然后比较再选择插入的位置等
for (int i = 1; i < abc.length ; i++) {
int insertIndex = i -1;
int insertValue = abc[i];
// 这里的数组下标是可以等于0
while (insertIndex >= 0 && insertValue < abc[insertIndex]){
// 将大的值往后移,直到找到合适的插入位置
abc[insertIndex+1] = abc[insertIndex];
insertIndex--;
}
// 退出循环后,就说明插入的位置找到了 加入判断,如果没有进去while的话,就不用赋值,插入位置不变
if (insertIndex + 1 != i) {
abc[insertIndex+1] = insertValue; } }
System.out.println(Arrays.toString(abc)); } }

快速排序

  • 一种双指针移动的排序,找个基准值
package src.datastructure;

import java.util.Arrays;

/**
* @Author: yhy
* @Time: 12:05
* 采用指针交换来做
*/
public class QuickSort2 {
public static void quickSort(int[] arr, int startIndex, int endIndex) {
// 递归结束:startIndex 大于等于endIndex的时候
if (startIndex >= endIndex) {
return; }
// 得到基准元素位置
int pivotIndex = partition(arr, startIndex, endIndex);
// 使用分治法递归数列的两部分
quickSort(arr, startIndex, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, endIndex);
} public static int partition(int[] arr, int startIndex, int endIndex) {
// 这里的交换次数更少了
int pivot = arr[startIndex];
int left = startIndex;
int right = endIndex;
// 退出循环的时候,说明已经检索到中间位置了
while (left != right){
// 分别去找到左边和右边停止的指针
while (left < right && arr[right] > pivot){
right--;
}
while (left < right && arr[left] <= pivot){
left++;
}
// 然后进行交换
if (left < right) {
int p = arr[left];
arr[left] = arr[right];
arr[right] = p;
}
}
// 一轮交换已经结束
// pivot和指针重合点交换
// 将基准值放到所对应的位置
int p = arr[left];
arr[left] = arr[startIndex];
arr[startIndex] = p;
return left; }
public static void main(String[] args) {
int[] arr = new int[]{4,2,3,6,15,7,1,9};
quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
} }

希尔排序

  • 希尔排序就是分组排序,将取一个间隔gap作为每次分的组数。
package src.datastructure;

import java.util.Arrays;

/**
* @Author: yhy
* @Time: 15:30
* 希尔排序
*/
public class ShellSort {
public static void main(String[] args) {
int[] abc = {1,9,-2,40,33};
// 希尔排序,要进行分组排序,同时依据是gap长度除2,每一次进行交换
// 用到了插入排序和冒泡排序的感觉
// 这是分组
for (int gap = abc.length/2; gap > 0; gap /= 2) {
// 这个for循环写法要注意
for (int i = gap; i < abc.length; i++) {
int j = i;
int temp = abc[j];
if (abc[j] < abc[j-gap]) {
while (j - gap >= 0 && temp < abc[j-gap]){
abc[j] = abc[j-gap];
j -= gap;
}
//将相对小索引的值变为一开始的
abc[j] = temp;
} } }
System.out.println(Arrays.toString(abc)); } }

归并排序

  • 利用了分治的思想,先分再合来排序。降低问题的难度,逐一突破。
package src.datastructure;

import java.util.Arrays;

/**
* @Author: yhy
* @Time: 0:06
*/
public class MergeSort {
public static void main(String[] args) {
// 自顶向下的归并排序
int[] abc = {1, 9, -2, 40, 33, 6, 5};
int[] temp = new int[abc.length];
mergeSort(abc, 0, abc.length - 1, temp);
System.out.println(Arrays.toString(abc)); } // 分加合
public static void mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2; //中间索引
//向左递归进行分解
mergeSort(arr, left, mid, temp);
//向右递归进行分解
mergeSort(arr, mid + 1, right, temp);
//合并
merge(arr, left, mid, right, temp); } } // 合方法
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int leftStart = left;
int rightStart = mid + 1;
int i = 0;
// 这里注意可以等于
while (leftStart <= mid && rightStart <= right) {
if (arr[leftStart] >= arr[rightStart]) {
temp[i++] = arr[rightStart++];
} else {
temp[i++] = arr[leftStart++];
}
}
while (leftStart <= mid) {
temp[i++] = arr[leftStart++];
} while (rightStart <= right) {
temp[i++] = arr[rightStart++];
} // copy array
i = 0;
int tempLeft = left;
while (tempLeft <= right) {
arr[tempLeft++] = temp[i++];
} } }

基数排序

  • 用到了十个桶,将每一个数据按照位数将其分割,百、十、个位数进行比较
package com.atguigu.sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date; public class RadixSort { public static void main(String[] args) {
int arr[] = { 53, 3, 542, 748, 14, 214}; // 80000000 * 11 * 4 / 1024 / 1024 / 1024 =3.3G
// int[] arr = new int[8000000];
// for (int i = 0; i < 8000000; i++) {
// arr[i] = (int) (Math.random() * 8000000); // 生成一个[0, 8000000) 数
// } radixSort(arr);
System.out.println("基数排序后 " + Arrays.toString(arr)); } //基数排序方法
public static void radixSort(int[] arr) { //根据前面的推导过程,我们可以得到最终的基数排序代码 //1. 得到数组中最大的数的位数
int max = arr[0]; //假设第一数就是最大数
for(int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
//得到最大数是几位数
int maxLength = (max + "").length(); //定义一个二维数组,表示10个桶, 每个桶就是一个一维数组
//说明
//1. 二维数组包含10个一维数组
//2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length
//3. 名明确,基数排序是使用空间换时间的经典算法
int[][] bucket = new int[10][arr.length]; //为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
//可以这里理解
//比如:bucketElementCounts[0] , 记录的就是 bucket[0] 桶的放入数据个数
int[] bucketElementCounts = new int[10]; //这里我们使用循环将代码处理 for(int i = 0 , n = 1; i < maxLength; i++, n *= 10) {
//(针对每个元素的对应位进行排序处理), 第一次是个位,第二次是十位,第三次是百位..
for(int j = 0; j < arr.length; j++) {
//取出每个元素的对应位的值
int digitOfElement = arr[j] / n % 10;
//放入到对应的桶中
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
//按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
int index = 0;
//遍历每一桶,并将桶中是数据,放入到原数组
for(int k = 0; k < bucketElementCounts.length; k++) {
//如果桶中,有数据,我们才放入到原数组
if(bucketElementCounts[k] != 0) {
//循环该桶即第k个桶(即第k个一维数组), 放入
for(int l = 0; l < bucketElementCounts[k]; l++) {
//取出元素放入到arr
arr[index++] = bucket[k][l];
}
}
//第i+1轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
bucketElementCounts[k] = 0; } } }
}
  • leetcode 347题
package src.datastructure;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; /**
* @Author: yhy
* @Time: 14:37
* leetcode #347
* 用到了桶排序的思想
*/
public class BucketSort {
// Given [1,1,1,2,2,3] and k = 2, return [1,2].
public static void main(String[] args) {
int[] arr = new int[]{1, 1, 1, 2, 2, 3};
int[] a = bucketsort(arr);
System.out.println(Arrays.toString(a));
System.out.println(maxReturn(a,2));
}
// 传入数组,返回数组
public static int[] bucketsort(int[] arr){
// 定义一个桶
int[] bucket = new int[10];
for (int val: arr ) {
bucket[val]++;
}
return bucket;
}
private static List maxReturn(int[] arr,int k){
int max = arr[0];
List<Integer> list = new ArrayList<>();
while (k >0) {
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
arr[i] = 0;
list.add(i);
}
}
max = 0;
k--;
}
return list;
} }

堆排序

不稳定,线性复杂度,完全二叉树。

大顶堆

结点大于两边子树,arr[i]>arr[2i+1]&&a[i]>a[2i+2],升序使用这个

package src.datastructure.sort;

import java.util.Arrays;

/**
* @Author: yhy
* @Date: 2020/3/19
* @Time: 12:30
*/
public class HeapSort {
public static void main(String[] args) {
int[] arr = {12, 3, 63, 6, 8};
heapsort(arr);
} public static void heapsort(int[] arr) {
int temp = 0;
System.out.println("堆排序");
//找到第一个大顶堆结构,然后才可以进行下面的代码
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
System.out.println(Arrays.toString(arr));
//交换数据,数组排序 调整堆结构+交换堆顶元素与末尾元素
for (int i = arr.length - 1; i > 0; i--) {
temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
adjustHeap(arr, 0, i);
}
System.out.println("排序后的" + Arrays.toString(arr)); } public static void adjustHeap(int[] arr, int i, int length) {
//不断调整,弄个大顶堆
//后面要进行交换
int temp = arr[i];
//寻找非叶子节点 最后的条件表示左子节点还可以往下寻找
for (int j = i * 2 + 1; j < length; j = j * 2 + 1) {
//左右节点的比较
if (j + 1 < length && arr[j] < arr[j + 1]) {
j++;
}
if (arr[j] > temp) {
arr[i] = arr[j];
i = j;
} else {
break;
} } arr[i] = temp; } }

小顶堆

结点小于两边子树

思想(借助树的结构完成排序)

  1. 将待排序序列构造成一个大顶堆
  2. 此时序列的最大值就是堆顶的根节点
  3. 将其与数组末尾元素交换,这样构造数组的最大值在右边
  4. 再将n-1个元素重新构造一个堆,这样就会得到n个元素的次小值,反复进行就可以得到一个有序的数组,完成排序

排序算法代码实现-Java的更多相关文章

  1. 第二章:排序算法 及其他 Java代码实现

    目录 第二章:排序算法 及其他 Java代码实现 插入排序 归并排序 选择排序算法 冒泡排序 查找算法 习题 2.3.7 第二章:排序算法 及其他 Java代码实现 --算法导论(Introducti ...

  2. 排序算法总结(基于Java实现)

    前言 下面会讲到一些简单的排序算法(均基于java实现),并给出实现和效率分析. 使用的基类如下: 注意:抽象函数应为public的,我就不改代码了 public abstract class Sor ...

  3. 八大排序算法总结与java实现(转)

    八大排序算法总结与Java实现 原文链接: 八大排序算法总结与java实现 - iTimeTraveler 概述 直接插入排序 希尔排序 简单选择排序 堆排序 冒泡排序 快速排序 归并排序 基数排序 ...

  4. 编程算法 - 高速排序算法 代码(C)

    高速排序算法 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 经典的高速排序算法, 作为一个编程者, 不论什么时候都要完整的手写. 代码: /* * m ...

  5. 常见排序算法题(java版)

    常见排序算法题(java版) //插入排序:   package org.rut.util.algorithm.support;   import org.rut.util.algorithm.Sor ...

  6. 动画展现十大经典排序算法(附Java代码)

    0.算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序. 非比较类排序: ...

  7. 常见排序算法总结(java版)

    一.冒泡排序 1.原理:相邻元素两两比较,大的往后放.第一次完毕,最大值在最大索引处. 即使用相邻的两个元素一次比价,依次将最大的数放到最后. 2.代码: public static void bub ...

  8. 排序算法大汇总 Java实现

    一.插入类算法 排序算法的稳定性:两个大小相等的元素排序前后的相对位置不变.{31,32,2} 排序后{2,31,32},则称排序算法稳定 通用类: public class Common { pub ...

  9. 排序算法的总结——Java实现

    前言 简单归纳一下最近学习的排序算法,如果有什么错误的地方还请大家指教. 本文介绍了七种经典排序算法,包括冒泡排序,选择排序,插入排序,希尔排序,归并排序,快速排序以及堆排序,并且讨论了各种算法的进一 ...

随机推荐

  1. angularjs中$parse的用法

    转载自:https://umur.blog/2014/02/25/advanced-angular-parse/ 高级Angular:$ parse 如果你想加强你的AngularJS知识,$ par ...

  2. Thinking in Java学习杂记(5-6章)

    Java中可以通过访问控制符来控制访问权限.其中包含的类别有:public, "有好的"(无关键字), protected 以及 private.在C++中,访问指示符控制着它后面 ...

  3. Python第六章-函数05-迭代器&生成器

    python作为一个既面向对象,又支持函数式编程的语言,函数的使用方面有很多特点. 比如:闭包,装饰器,迭代器等 函数的高级应用 容器:生活中常见的容器有哪些?袋子,盆子,水杯,书包,铅笔盒... 容 ...

  4. 【LeetCode】141.环形链表

    题目描述 141.环形链表 给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中 ...

  5. Make编译Ardupilot源码的两种方法

    编译环境准备 ​ Ardupilot源码下载和PX4 toolchain工具链下载 ​ (见https://www.cnblogs.com/BlogsOfLei/p/7707485.html) ​ 注 ...

  6. 磅日波浪分析4H 20190927

    磅日的短线调整预计在132结束 目前已显现出ABC调整末端. 未来预计开启第五浪升势 破前期反弹高点.

  7. 牛客挑战赛38 (A - D)

    A - 多边形与圆 题目链接 题意 给出一个多边形的坐标和圆的半径, 多边形可以在圆内滚动, 问点 1 在成为转动中心到下一次成为转动中心的过程中经过的路程长度. 题解 枚举点 2 - n 成为转动中 ...

  8. Django之auth用户认证

    auth模块 from django.contrib import auth django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: authenticate()    提供 ...

  9. FCOS : 找到诀窍了,anchor-free的one-stage目标检测算法也可以很准 | ICCV 2019

    论文提出anchor-free和proposal-free的one-stage的目标检测算法FCOS,不再需要anchor相关的的超参数,在目前流行的逐像素(per-pixel)预测方法上进行目标检测 ...

  10. STM32F103ZET6的中断管理

    1.STM32的中断 STM32的中断管理是属于内核部分的,所以中断管理的寄存器也是属于内核组,不属于芯片外设,在查看相关资料的时候,需要查看相对应的内核手册. STM32F103ZET6是Corte ...