排序算法
排序也称排序算法,排序是将一组数据,依次指定的顺序进行排序的过程
排序的分类:
1.内部排序
将需要处理的所有数据都加载到内部存储器中进行排序
2.外部排序法
数据量过大,无法全部加载到内存当中,需要加注外部存贮进行排序
衡量一个算法的效率
时间频度
常数项可以忽略
2n+20和20随着时间的增长20就能够忽略
系数也可以忽略
一次项的系数也能忽略
常见的算法时间复杂度由小到大依次为:O(1)<O(log2b)<O(N)<O(nlog2n)<O(n2)<O(n3)<O(nk)
所以要尽量的避免指数级的出现
时间复杂度
时间频度:一个算法话费的是时间与算法中语句执行的次数成正比,哪个算法中语句执行的次数多,他花费的时间就多。一个算法中的语句执行语句的行数就称为时间频度T(n).
T(n)=O(f(n))
平均时间复杂度和最坏时间复杂度
一般判断的时间都是用最坏时间复杂度,更能衡量算法的效率
算法的控件复杂度简介
做算法分析的时候一般用到的是时间复杂度,很多时候都是用空间换时间,硬件很充足。
八种排序算法
冒泡排序
基本介绍:通过对待排序列从前向后,依次比较相邻元素的值,若发现逆序就交换,使值比较大的元素向后面移动
如果本来就有序,就会有很多不必要的比较,设置条件。
循环执行
第一趟排序 从第一个元素开始和后面的比较如果发现逆序就交换
(1) 一共进行数组大小的-1次大循环
(2) 每一趟排序的次数在变少
(3)如果我们发现在某一次没有发生变化,能够提前结束
package com.baicai.sort;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int arr[] = {3, 8, -2, 7, 5};
bubbleSort(arr);
}
public static void bubbleSort(int[] arr){
//1.第一趟让最大的放在最后面
//临时变量
int temp = 0;
//当没有发生交换的时候就能退出循环了 -- 小型算法常用技巧
boolean flag = false;
for(int i = 0;i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
//如果前面的数比后面的大就交换
if (arr[j] > arr[j + 1]) {
flag = true;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
if(!flag){ //一次排序的过程中一个交换都没有
break;
}else{
flag = false; //重置flag
}
System.out.println(Arrays.toString(arr));
}
}
}
选择排序
选择排序也称为内部排序
1.外循环以第一个为基准,遍历数组发现最小值,与基准交换
2.将第二个设置为基准,遍历数组发现最小值,与基准交换
package com.baicai.sort;
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args){
int[] arr = {101, 56, 77, 23, 1, 6, 3};
selectSort(arr);
}
/*
*
* 选择排序数组
* */
public static void selectSort(int[] arr) {
int minIndex = 0;
//循环遍历数组交换
for(int i = 0;i < arr.length - 1; i++){
int min = arr[i];
//比较大小交换值
for(int j = i; j < arr.length; j++){
if(min > arr[j]){
min = arr[j];
minIndex = j;
}
}
//当有值比我们的基准值要小的时候
if(i != minIndex) {
//交换值
arr[minIndex] = arr[i];
arr[i] = min;
}
}
System.out.println(Arrays.toString(arr));
}
}
插入排序
插入排序的基本思想:把n个待排序的元素堪称一个有序列表和无序列表,开始有序列表只有一个元素,无序表里面包含n-1个元素,排序过程中每次无序取出一个元素的排序码进行比较,将他插入到有序表中的适当位置。
package com.baicai.sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/*
*
* 插入排序法*/
public class insertSortDome {
public static void main(String[] args){
int[] arr = {-1, 101, 34, 119, 1};
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.printf(date1Str);
insertSort2(arr);
Date data2 = new Date();
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date2Str = simpleDateFormat2.format(data2);
System.out.printf(date2Str);
}
//插入排序
public static void insertSort(int[] arr) {
for(int i = 1;i < arr.length; i++){
for(int j = i;j > 0; j--){
if(arr[j] < arr[j - 1]){
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
public static void insertSort2(int[] arr){
for(int i = 0;i < arr.length; i++){
int insertVal = arr[i];
int insertIndex = i - 1;
//给insertIndex >=0 保证
while(insertIndex >= 0 && insertVal < arr[insertIndex]){
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
arr[insertIndex + 1] = insertVal;
}
}
}
希尔排序
希尔排序法介绍
希尔排序是希尔在1959年提出的得一种排序算法,也是一种插入排序。简单地插入排序改进之后的更加高效的版本,也称为缩小增量排序。
希尔排序法的基本思想
希尔排序把记录按下标的一定增量分组,对每组直接用插入排序算法排序,随着增量逐渐减少,每组包含的关键词越来越多,当增量减到1的时候整个文件就被分成一组正好结束
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WUoROkZV-1604841846549)(C:\Users\junji\Desktop\iweb\笔记\图片\QQ截图20201102170429.png)]
package com.baicai.sort;
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args){
int[] arr = {9,2,3,5,7,6,1,4,0,8};
shellSort(arr);
}
//交换法
public static void shellSort(int[] arr){
int temp = 0;
//希尔排序第一轮
for(int gap = arr.length / 2; gap > 0; gap = gap / 2) {
for (int i = gap; i < arr.length; i++) {
//遍历各组中的元素(首先分成5组)
for (int j = i - gap; j >= 0; j -= gap) {
if (arr[j] > arr[j + gap]) {
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
//位移法
public static void ShellSort2(int[] arr){
for(int gap = arr.length / 2; gap > 0; gap = gap / 2) {
for (int i = gap; i < arr.length; i++) {
//遍历各组中的元素(首先分成5组)
int j = i;
int temp = arr[j];
//给insertIndex >=0 保证
while(j -gap >= 0 && temp < arr[j - gap]){
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
}
}
System.out.println(Arrays.toString(arr));
}
}
快速排序
快速排序:对冒泡排序的一种改良。
基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据要小,然后按照这个方法对这两部分数据分别进行快速排序整个过程递归进行变成有序序列。
package com.baicai.sort;
import java.util.Arrays;
public class quickSort {
public static void main(String[] args){
int[] arr = {1,6,3,5,4,8,9};
quickSort(arr,0, arr.length - 1);
}
public static void quickSort(int[] arr,int left,int right){
int l = left; //左面的下标
int r = right; //右面的下标
//pivot 是中间值
int privot = arr[(left + right) / 2];
int temp = 0; //交换时候使用的临时变量
//比pivot大值放到右面
while(l < r){
//左面的值要是比中间的值小就继续+1
while(arr[l] < privot){
l++;
}
while(arr[r] > privot){
r--;
}
if(l >= r){
break;
}
//交换值
temp = arr[r];
arr[r] = arr[l];
arr[l] = temp;
if(arr[l] == privot){
r--;
}
if(arr[r] == privot){
l++;
}
}
//使用这句话可以让
if(l == r){
l++;
r--;
}
//向左递归
if(left < r){
quickSort(arr, left, r);
}
//向右递归
if(right > l){
quickSort(arr, l, right);
}
System.out.println(Arrays.toString(arr));
}
}
归并排序
利用归并的思想实现排序的方法,该法采用f分而治之的思想。
分:将数组分成挺多行
治:将两个已经有序的序列合并为一个有序的最终序列。
import java.util.Arrays;
public class MergetSort {
public static void main(String[] args){
int arr[] = {8,6,7,9,0,3,4,2,10,5,1};
int[] temp = new int[arr.length];
mergeSort(arr, 0,arr.length - 1,temp);
System.out.println(Arrays.toString(arr));
}
//分+和的方法
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);
}
}
/**
*
* @param arr 排序的原始数组
* @param left 左面有序序列的初始数组
* @param mid 中间索引
* @param right 左面索引
* @param temp 临时数组
*
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
System.out.println();
int i = left; //初始化i,左边序列的初始索引
int j = mid + 1; //初始化j,右边序列的初始化索引
int t = 0; //指向temp数组的当前索引
//先把左右两边的有序序列的数据填充到temp数组
//直到左右两边的序列,有一边助理完毕为止
while(i <= mid && j <= right){ //继续走
//如果左面的有序序列的当前元素,小于等于右面有序序列的当前元素
//将左面的当前元素拷贝到temp数组
if(arr[i] <= arr[j]){
temp[t] = arr[i];
t += 1;
i += 1;
}else{ //反之,将右边的有序序列的当前元素填充到temp数组当中
temp[t] = arr[j];
t++;
j++;
}
}
//将剩余的数组一遍万千填充到temp中
while(i <= mid){ //左面的有序序列还有剩余的元素,就全部填充到temp中
temp[t] = arr[i];
t++;
i++;
}
//将temp数组拷贝到arr数组当中
while(j <= right){ //右面还有元素
temp[t] = arr[j];
t++;
j++;
}
//将temp数组的元素拷贝到arr中
//并不是每次都拷贝所有
t = 0;
int tempLeft = left;
System.out.println(tempLeft);
System.out.println(right);
while(tempLeft <= right){
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
}
基数排序
1.基数排序属于分配式排序,又称为桶子法,通过各建的值,将要排序的元素分配要某些桶当中达到排序的作用
2.基数排序属于稳定的排序,基数排序是效率最高的稳定排序算法
3.基数排序是桶排序的扩展
4.将整数按位数切隔成不同的数字,然后按每个位数比较
1.将每个元素的个位数取出,然后放在对应的桶(一个一维数组)
2.然后将桶当中的数据取出来放到原本的数组中
3.然后将每个元素的十位取出,放到对应的桶当中
4.然后依次取出放到原本的数组当中
5.依次下去 到最大的呢位就完成了排序
public class RadixSort {
public static void main(String[] args) {
int[] arr = {53, 3, 542, 748, 214};
radixSort1(arr);
}
//以个位为基准进行排序
public static void radixSort1(int[] arr) {
//首先看最大的数字有几位
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.极端情况所有的都是有一位下标全部一样
//2.为了防止溢出,每一个一维数组大小都为arr.length
int[][] bucket = new int[10][arr.length];
//为了记录每一个桶中实际上放了多少个数据,定义一个一维数组记录每个桶放入的数据
//记录了每个组有的数据
int[] bucketElementCount = 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][bucketElementCount[digitOfElement]] = arr[j];
bucketElementCount[digitOfElement]++;
}
//按照这个桶的数据取出数组
int index = 0;
//遍历每个桶,并且将桶中的数据放到原来的数组当中
for (int k = 0; k < bucketElementCount.length; k++) {
//桶中有数据,我们才放到原数组当中
if (bucketElementCount[k] != 0) {
//说明里面有数据遍历整个数组
for (int l = 0; l < bucketElementCount[k]; l++) {
//将元素取出
arr[index] = bucket[k][l];
index++;
}
}
//每一轮结束的时候
bucketElementCount[k] = 0;
}
System.out.println(Arrays.toString(arr));
}
}
}
说明:
1.基数排序是对传统桶排序的扩展,速度很快。
2.基数排序是经典的空间换时间的方式,内存占用很大,海量数据造成OutOfMemoryError
3.基数排序的时候稳定(稳定:就是指数组中相同的数字在排序之后先后顺序没有发生变化,不稳定就是发生了变化)