排序算法
Posted xiaoaiying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法相关的知识,希望对你有一定的参考价值。
一、冒泡排序
常用的也是简单的排序算法
个人理解:
- 步骤:往后对比、找最值、换最值
第一层i循环次数就是要排序数组的个数
第二层j循环可以每次都从第一个数开始往后对比,如果大小于就交换,保证对比值一直都是最值
第二层循环条件中可以减去i,因为i每次循环后都会得一个最值往后面冒泡,即i下标后面的数已经是排序好的了不用再次对比了
//冒泡排序
public class BubbleSort {
public static void main(String[] args){
int[] arr = {3,9,-1,10,20};
System.out.println("原数组:"+Arrays.toString(arr));
bubbleSort(arr);
}
public static void bubbleSort(int[] arr){
int temp = 0;
boolean flag = false;//标识变量,表示一轮对比中是否发生交换
for (int i=0;i<arr.length;i++){
//j为什么要减i,因为第i次循环时,已经有i个最大的数在后面从小到大排好了。
// 为什么要减1:因为需要留出一个,让当前数和后面的对比。不减1,当当前元素即j到达最后一个,由于后面没有元素则会溢出
for (int j=0;j<arr.length-i-1;j++){
if (arr[j]>arr[j+1]){ //即通过前后两个数对比,大于就交换,让当前一直保持最大直到比到最后,
temp =arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
}
二、插入排序
个人理解:
- 步骤:往前对比,找合适插入位置、记录当前值、移位、当前值插入合适位置
第一层i循环次数也是要排序数组的个数
public class InsertSort {
public static void main(String[] args){
int[] arr = {3,9,-1,10,20};
System.out.println("原数组:"+ Arrays.toString(arr));
insertSort(arr);
System.out.println("排序后:"+Arrays.toString(arr));
}
public static void insertSort(int[] arr){
int preIndex;
int current;
for (int i = 1; i < arr.length; i++) {
preIndex = i; //当前元素下标
current = arr[i];//当前元素值
while (preIndex>0 && arr[preIndex-1] > current){
arr[preIndex] = arr[preIndex-1];//把数往前移动一位
preIndex--;
}
//移动完后把当前值插入到对应位置
arr[preIndex] = current;
}
}
}
三、选择排序
- 步骤:往后对比,一轮循环记录最小值和最小值的下标,直接交换最小值到前面
第一层i循环次数也是要排序数组的个数
//选择排序
public class SelectSort {
public static void main(String[] args){
int[] arr = {3,9,-1,10,20};
System.out.println("原数组:"+Arrays.toString(arr));
selectSort(arr);
System.out.println("排序后:"+Arrays.toString(arr));
}
public static void selectSort(int[] arr) {
if (arr.length<2){
return;
}
int minIndex; //假定最小数下标
int min; //存储最小值
for (int i = 0; i < arr.length-1; i++) {
minIndex = i; //假定最小值下标等于循环时第一个元素的下标
min = arr[i]; //假定最小值为循环中的第一个元素
for (int j = i+1; j < arr.length; j++) {
if (arr[j] < min){ //arr[i] 相当于是最小值
min = arr[j];
minIndex = j;
}
}
//把最小值交换到前面。
if (minIndex != i){
arr[minIndex] = arr[i];
arr[i] = min;
}
}
}
}
四、归并排序
//归并排序
public class MergetSort {
public static void main(String[] args) {
int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
System.out.println("原数组:"+ Arrays.toString(arr));
int[] temp = new int[arr.length];
mergetSort(arr,0,arr.length-1,temp);
System.out.println("排序后:"+Arrays.toString(arr));
}
//分+合的方法
public static void mergetSort(int[] arr,int left,int right,int[] temp){
if (left<right){
int mid = (left+right)/2;
//向左递归分解
mergetSort(arr,left,mid,temp);
//向右递归分解
mergetSort(arr,mid+1,right,temp);
//分解一次就合并一次
merget(arr,left,mid,right,temp);
}
}
//合并两个有序数组的方法
/**
*
* @param arr 数组原始索引
* @param left 左边有序数组的初始索引
* @param mid 中间索引
* @param right 右边数组索引
* @param temp 中转数组--即合并两个数组的有序数组
*/
public static void merget(int[] arr,int left,int mid,int right ,int[] temp){
int l = left; //初始化i,左边初始索引
int r = mid+1; //右边初始索引
int t = 0;
//先把左右两边(有序)数组按照规则填充打temp
//左右两边有序数组,有一边处理完成,则把另一边的直接拷贝就行了
while (l <= mid && r<=right){
if (arr[l] <= arr[r]) { //左数组元素比右数组元素小
temp[t] = arr[l]; //左边元素加入数组
t+=1; //有序数组下标加1
l+=1; //左边数组下标加1
}else { //反之,右边数组元素比左数组元素小
temp[t] = arr[r]; //左边元素加入数组
t+=1; //有序数组下标加1
r+=1; //左边数组下标加1
}
}
//右边数组遍历完,但是左边没有遍历完
while (l <= mid){
temp[t] = arr[l]; //左边元素加入数组
t+=1; //有序数组下标加1
l+=1; //左边数组下标加1
}
//左边数组遍历完,但是右边没有遍历完
while (r <= right){
temp[t] = arr[r]; //左边元素加入数组
t+=1; //有序数组下标加1
r+=1; //左边数组下标加1
}
//把temp数组元素拷贝到arr
t = 0;
int tempLeft = left;
while (tempLeft <= right){ //把排序好的数组拷贝回原数组
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
}
五、快速排序
选择一个中轴值,小在左,大在右,一直分治
public class QuickSort2 {
public static void main(String[] args){
int[] arr = {101,34,119,1,-1,90,123};
System.out.println("原数组:"+ Arrays.toString(arr));
quickSort(arr,0,arr.length-1);
System.out.println("排序后:"+Arrays.toString(arr));
}
public static void quickSort(int[] arr,int left,int right){
if(left>=right){
return;
}
int l = left;//记录最右边
int r = right;//记录最左边
// 1-基于基准值交换----快速排序就是找一个基准值,把小的放基准值前面,大的放基准值后面
int pivot = arr[l];//获取基准值=第一个元素
int temp = 0;//临时变量,交换使用
while (l<r){
//由于是在同一个数组操作,所以需要左右两边一起操作
//由于要把基准值交换,所以右边最后一定是小于基准值的,所以需要优先判断,即从右边走
while (arr[r] >= pivot && l<r){
//右边如果小于基准值,下标减1
r--;//保证下标r的值小于基准值
}
while (arr[l] <= pivot && l<r){
//左边如果小于基准值,下标加1
l++; //保证下标l的值大于基准值
}
//因为找到了左边大于基准值,右边小于基准值的两个值,所有左右两边值进行交换
if (l<r){
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
}
//2-基准值归位-----循环结束后l肯定等于r,并且由于是从右边开始走的所以最后下标r的值一定小于基准值,直接交换即可
arr[left] = arr[r];
arr[r] = pivot;
//3-递归----最后左右递归一直分治,基准值已经在合适的位置了就不用参与排序了
//左递归
quickSort(arr,left,r-1);
//右递归
quickSort(arr,r+1,right);
}
}
六、基数排序
//基数排序
public class RadixSort {
public static void main(String[] args){
int[] arr = {53,3,542,748,14,214};
System.out.println("原数组:"+ Arrays.toString(arr));
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];
}
}
//2-得到最大数是几位数
int maxLength = (max+"").length();
//定义一个二维数组,表示10个桶.每一行即一维数组表示一个桶
// 为了防止放入数的时候,数据溢出,则每个一维数组(),大小定位arr.length
// 明确:基数排序是使用空间换时间。
int[][] bucket = new int[10][arr.length];
//为了记录每个桶中实际存放多少个数据,定义一个一维数组来记录各个桶放入数据的个数
int[] bucketElementCounts = new int[10]; //对应存放十个桶中,最后一个元素的下标,即桶存储了几个数据
//3-循环
for (int i = 0,n=1; i < maxLength; i++,n*=10) {
//针对每个元素对应位进行排序处理 ,第一是个位,第二是百位,第三是千位 .......
for (int j = 0; j < arr.length; j++) {
//取出每个元素个位数,相当于要存放桶的下标
int digitaOfElement = arr[j]/n % 10;
//放入对应的桶中
//bucketElementCounts[digitaOfElement] 即存放在一行(桶)中的哪个位置
bucket[digitaOfElement][bucketElementCounts[digitaOfElement]] = arr[j];
//对应桶元素下标后移一位,也相当于对应桶记录元素个数数组加1
bucketElementCounts[digitaOfElement]++;
}
//按照桶的顺序依次取出数据放入原来的数组
int index = 0;
for (int k = 0; k < bucketElementCounts.length; k++) {
//如果桶中有数据,才放入原数组中
if (bucketElementCounts[k] != 0){ //桶对应记录!=0,即记录的下标不为0,即该桶不为空
for (int l = 0; l < bucketElementCounts[k]; l++) {
//取出元素放入到原数组
arr[index++] = bucket[k][l];
}
}
//一轮处理后,需要将每个bucketElementCounts[k] = 0,即指向每个桶对应记录数组的下标都置会0,即初始
bucketElementCounts[k] = 0;
}
}
}
}
七、桶排序
八、希尔排序
//希尔排序
public class ShellSort {
public static void main(String[] args){
int[] arr = {8,9,1,7,4,2,3,5,4,6,0};
System.out.println("原数组:"+ Arrays.toString(arr));
shellSort2(arr);
System.out.println("排序后:"+Arrays.toString(arr));
}
//希尔排序----交换法
public static void shellSort(int[] arr){
int temp;
for (int gap = arr.length/2; gap > 0; gap /= 2) { // 分组,每组一半
for (int i = gap; i < arr.length ; i++) { //从gap开始往前对应一个元素对比 这里是gap开始
for (int j = i-gap; j >= 0; j-=gap) { //这里是gap对应的元素
//如果当前元素大于加上步长后的那个元素,就要交换
if (arr[j] > arr[j+gap]){
temp = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = temp;
}
}
}
}
}
//希尔排序----移位法
public static void shellSort2(int[] arr){
int temp;
for (int gap = arr.length/2; gap > 0; gap /= 2) { // 分组,每组一半
// 从gap个元素,逐个对其所在的组进行直接插入排序
for (int i = gap; i < arr.length ; i++) {
int j = i;
temp = arr[j]; //存放当前值
// if (arr[i] < arr[j-gap]){
while (j-gap >= 0 && arr[j-gap] > temp){
//移动
arr[j] = arr[j-gap];
j-=gap;
}
//当退出循环,说明找到插入位置
arr[j] = temp;
// }
}
}
}
}
以上是关于排序算法的主要内容,如果未能解决你的问题,请参考以下文章