java排序:
1.冒泡排序:
a.未优化冒泡:
import java.util.Arrays;
//冒泡排序
public class BubbleSort_01 {
public static void main(String[] args) {
int a[]={3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
//记录比较次数
int count=0;
//i=0,第一轮比较
for (int i = 0; i < a.length-1; i++) {
//第一轮,两两比较
for (int j = 0; j < a.length-1-i; j++) {
if (a[j]>a[j+1]) {
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
count++;
}
}
System.out.println(Arrays.toString(a));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
System.out.println("一共比较了:"+count+"次");//一共比较了:105次
}
}
b.优化后的冒泡:
如果有一次冒泡后其余的数据是有序的这样可以节约资源:
import java.util.Arrays;
public class BubbleSort1_01
{
public static void main(String[] args)
{
int a[]={3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
int count=0;
for (int i = 0; i < a.length-1; i++)
{
boolean flag=true;
for (int j = 0; j < a.length-1-i; j++)
{
if (a[j]>a[j+1])
{
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
flag=false;
}
count++;
}
if (flag) //这里如果是ture则说明前面的已经是有序的了!
{
break;
}
}
System.out.println(Arrays.toString(a));// [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
System.out.println("一共比较了:"+count+"次");//一共比较了:95次
}
}
2.选择排序:
import java.util.Arrays;
//选择排序:先定义一个记录最小元素的下标,然后循环一次后面的,找到最小的元素,最后将他放到前面排序好的序列。
public class SelectSort_02 {
public static void main(String[] args) {
int a[]={3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
for (int i = 0; i < a.length-1; i++) {
int index=i;//标记第一个为待比较的数
for (int j = i+1; j < a.length; j++) { //然后从后面遍历与第一个数比较
if (a[j]<a[index]) { //如果小,就交换最小值
index=j;//保存最小元素的下标
}
}
//找到最小值后,将最小的值放到第一的位置,进行下一遍循环
int temp=a[index];
a[index]=a[i];
a[i]=temp;
}
System.out.println(Arrays.toString(a));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
}
}
3.插入排序:
通过插入排序,i前面的已经是有序的,用变量inserIndex储存位置的数。然后再依次将这个数与前面的比较,如果小于前面的前面的一个往后移,让i-1的位置空出来,然后将inserIndex与i-2处比较直到出现了一个大于inserIndex的数然后插入进去
import java.util.Arrays;
//插入排序:定义一个待插入的数,再定义一个待插入数的前一个数的下标,然后拿待插入数与前面的数组一一比较,最后交换。
public class InsertSort_03 {
public static void main(String[] args) {
int a[]={3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
for (int i = 0; i < a.length; i++) { //长度不减1,是因为要留多一个位置方便插入数
//定义待插入的数
int insertValue=a[i];
//找到待插入数的前一个数的下标
int insertIndex=i-1;
while (insertIndex>=0 && insertValue <a[insertIndex]) {//拿a[i]与a[i-1]的前面数组比较
a[insertIndex+1]=a[insertIndex];
insertIndex--;
}
a[insertIndex+1]=insertValue;
}
System.out.println(Arrays.toString(a));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
}
}
4.希尔排序:
个人理解:(图画的比较烂>︿<)
import java.util.Arrays;
//希尔排序:插入排序的升级
public class ShellSort_04 {
public static void main(String[] args) {
int a[]={3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
int count=0;//比较次数
for (int gap=a.length / 2; gap > 0; gap = gap / 2) {
//将整个数组分为若干个子数组
for (int i = gap; i < a.length; i++) {
//遍历各组的元素
for (int j = i - gap; j>=0; j=j-gap) {
//这里的j=j-gap,是让后面每一拍的个数多余2个的时候,让左边的依次想要右边的
//交换元素
if (a[j]>a[j+gap]) {
int temp=a[j];
a[j]=a[j+gap];
a[j+gap]=temp;
count++;
}
}
}
}
System.out.println(count);//16
System.out.println(Arrays.toString(a));//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
}
}
5.快速排序:
https://blog.youkuaiyun.com/qq_26122557/article/details/79458649
public class QuickSort {
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基准位
temp = arr[low];
while (i<j) {
//这里每次循环后i所指向的值必定小于temp,j指向的值大于temp,当i,j相邻的时候。此时如果执行i++,那么i指向的值是大于基准值的,如果交换会让左边temp所在的位置的值大于temp
//先看右边,依次往左递减
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边,依次往右递增
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最后将基准为与i和j相等位置的数字交换
arr[low] = arr[i];
arr[i] = temp;
//递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
}
public static void main(String[] args){
int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
quickSort(arr, 0, arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
6.归并排序:
import java.util.Arrays;
//归并排序
public class MergeSort_06 {
public static void main(String[] args) {
int a[]={3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
//int a[]={5,2,4,7,1,3,2,2};
int temp[]=new int[a.length];
mergesort(a,0,a.length-1,temp);
System.out.println(Arrays.toString(a));
}
private static void mergesort(int[] a, int left, int right, int[] temp) {
//分解
if (left<right) {
int mid=(left+right)/2;
//向左递归进行分解
mergesort(a, left, mid, temp);
//向右递归进行分解
mergesort(a, mid+1, right, temp);
//每分解一次便合并一次
merge(a,left,right,mid,temp);
}
}
/**
*
* @param a 待排序的数组
* @param left 左边有序序列的初始索引
* @param right 右边有序序列的初始索引
* @param mid 中间索引
* @param temp 做中转的数组
*/
private static void merge(int[] a, int left, int right, int mid, int[] temp) {
int i=left; //初始i,左边有序序列的初始索引
int j=mid+1;//初始化j,右边有序序列的初始索引(右边有序序列的初始位置即中间位置的后一位置)
int t=0;//指向temp数组的当前索引,初始为0
//先把左右两边的数据(已经有序)按规则填充到temp数组
//直到左右两边的有序序列,有一边处理完成为止
while (i<=mid && j<=right) {//感觉有点田径赛马的感觉( o=^•ェ•)o ┏━┓)
//如果左边有序序列的当前元素小于或等于右边的有序序列的当前元素,就将左边的元素填充到temp数组中
if (a[i]<=a[j]) {
temp[t]=a[i];
t++;//索引向后移
i++;//i后移
}else {
//反之,将右边有序序列的当前元素填充到temp数组中
temp[t]=a[j];
t++;//索引向后移
j++;//j后移
}
}
//把剩余数据的一边的元素填充到temp中
while (i<=mid) {
//此时说明左边序列还有剩余元素
//全部填充到temp数组
temp[t]=a[i];
t++;
i++;
}
while (j<=right) {
//此时说明左边序列还有剩余元素
//全部填充到temp数组
temp[t]=a[j];
t++;
j++;
}
//将temp数组的元素复制到原数组
t=0;
int tempLeft=left;
while (tempLeft<=right) {
a[tempLeft]=temp[t];
t++;
tempLeft++;
}
}
}
7.堆排序:
public class Heap_Sort_07 {
public static void main(String[] args) {
int a[]={3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
sort(a);
System.out.println(Arrays.toString(a));
}
public static void sort(int[] arr) {
int length = arr.length;
//构建堆
buildHeap(arr,length);
for ( int i = length - 1; i > 0; i-- ) {
//将堆顶元素与末位元素调换
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
//数组长度-1 隐藏堆尾元素
length--;
//将堆顶元素下沉 目的是将最大的元素浮到堆顶来
sink(arr, 0,length);
}
}
private static void buildHeap(int[] arr, int length) {
for (int i = length / 2; i >= 0; i--) {//运行结束后i指向的长度为length树的最后叶节点的父亲(如果最后是一个单叶子节点结尾)如果是双叶子节点结尾则是最后一对叶子节点父亲的第一个右兄弟,意图是在大树了里面选择最小的树创建堆
sink(arr,i, length);
}
}
private static void sink(int[] arr, int index, int length) {
int leftChild = 2 * index + 1;//左子节点下标,。
int rightChild = 2 * index + 2;//右子节点下标//没有右节点虚拟一个右节点
int present = index;//要调整的节点下标
//下沉左边
if (leftChild < length && arr[leftChild] > arr[present]) {//leftChild < length判断leftChild是否存在
present = leftChild;
}
//下沉右边
if (rightChild < length && arr[rightChild] > arr[present]) {//rightChild < length判断rightChild是否存在
present = rightChild;
}
//如果下标不相等 证明调换过了
if (present != index) {
//交换值
int temp = arr[index];
arr[index] = arr[present];
arr[present] = temp;
//继续下沉
sink(arr, present, length);
}
}
}
8.计数排序:
基本思想是:1.一个全是整数的数组 2.他的范围是在min到max之间。 3 我们可以设置一个计数数组,数组的大小为max-min+1,数组的
下标代表min到max的所有整数,数组里面的内容是小于等于下标数的个数。 4. 设置一个输出数组,与原数组大小一样。由于计数数组里面的内容表示小于等于下标的原数组数的个数。我们可以把我们此时要写入out数组的原数组的数拿出来把其他小于等于这个数假设已将放在了前面,此时该数应该放到out数组的(出现的次数-1)下标处,并更新计数数组的值:count[array[i]-min]–;
import java.util.Arrays;
public class T1 {
public static void main(String[] args) {
int[] array = { 4, 2, 2, 8, 3, 3, 1 };
// 找到数组中最大的值 ---> max:8
int max = findMaxElement(array);
int min = findMinElement(array);
int[] sortedArr = countingSort(array, max-min + 1, min);
System.out.println("计数排序后的数组: " + Arrays.toString(sortedArr));
}
private static int findMaxElement(int[] array) {
int max = array[0];
for (int val : array) {
if (val > max)
max = val;
}
return max;
}
private static int findMinElement(int[] array) {
int min = array[0];
for (int val : array) {
if (val < min)
min = val;
}
return min;
}
private static int[] countingSort(int[] array, int range,int min) { //range:8-1+1
int[] output = new int[array.length];
int[] count = new int[range];
//初始化: count1数组
for (int i = 0; i < array.length; i++) {
count[array[i]-min]++;
}
//计数: count2数组,累加次数后的,这里用count2区分
for (int i = 1; i < range; i++) {
count[i] = count[i] + count[i - 1];
}
//排序:最后数组
for (int i = 0; i < array.length; i++) {
output[count[array[i]-min] - 1] = array[i];
count[array[i]-min]--;
}
return output;
}
}
9.桶排序:
算法步驟
设置一个bucketSize(该数值的选择对性能至关重要,性能最好时每个桶都均匀放置所有数值,反之最差),表示每个桶最多能放置多少个数值;
遍历输入数据,并且把数据依次放到到对应的桶里去;
对每个非空的桶进行排序,可以使用其它排序方法(这里递归使用桶排序);
从非空桶里把排好序的数据拼接起来即可。
import java.util.ArrayList;
public class T3 {
//在链表中添加元素的同时需要进行元素的排序
public static void sort(ArrayList<Integer> list, int i) {
if (list == null)
list.add(i);
//这里采用的排序方式为插入排序
else {
int flag = list.size() - 1;
while (flag >= 0 && list.get(flag) > i) {
if (flag + 1 >= list.size())
list.add(list.get(flag));
else
list.set(flag + 1, list.get(flag));
flag--;
}
if (flag != (list.size() - 1))
//注意这里是flag+1,自己可以尝试将这里换成flag看看,会出现数组越界的情况
list.set(flag + 1, i);
else
list.add(i);
}
}
public static void Bucketsort(int[] num, int sum) {
//遍历得到数组中的最大值与最小值
int min = Integer.MAX_VALUE;//Integer.MAX_VALUE表示int数据类型的最大取值数:2 147 483 647
//Integer.MIN_VALUE表示int数据类型的最小取值数:-2 147 483 648
int max = Integer.MIN_VALUE;
for (int i = 0; i < num.length; i++) {
min = min <= num[i] ? min : num[i];
max = max >= num[i] ? max : num[i];
}
//求出每个桶的长度,这里必须使用Double
double size = (double) (max - min + 1) / sum;
ArrayList<Integer> list[] = new ArrayList[sum];
for (int i = 0; i < sum; i++) {
list[i] = new ArrayList<Integer>();
}
//将每个元素放入对应的桶之中同时进行桶内元素的排序
for (int i = 0; i < num.length; i++) {
System.out.println("元素:" + String.format("%-2s", num[i]) + ", 被分配到" + (int) Math.floor((num[i] - min) / size) + "号桶");
sort(list[(int) Math.floor((num[i] - min) / size)], num[i]);//j将插入的i与桶内的其他进行排序
}
System.out.println();
for (int i = 0; i < sum; i++) {
System.out.println(String.format("%-1s", i) + "号桶内排序:" + list[i]);
}
System.out.println();
//顺序遍历各个桶,得出我们 已经排序号的序列
for (int i = 0; i < list.length; i++) {
if (list[i] != null) {
for (int j = 0; j < list[i].size(); j++) {
System.out.print(list[i].get(j) + " ");
}
}
}
System.out.println();
System.out.println();
}
public static void main(String[] args) {
int[] num = {7, 4, 9, 3, 2, 1, 8, 6, 5, 10};
long startTime = System.currentTimeMillis();
//这里桶的数量可以你自己定义,这里我就定义成了3
Bucketsort(num, 3);
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间: " + (endTime - startTime) + "ms");
}
}
10.基数排序:
原理:按照权重从个位往十位排序:0
import java.util.ArrayList;
public class T3 {
//将所有的数组合并成原来的数组
public static void merge(ArrayList<Integer> list[],int num[]) {
int k=0;
for(int i=0;i<list.length;i++) {
if(list[i]!=null) {
for(int j=0;j<list[i].size();j++) {
num[k++]=list[i].get(j);
System.out.print(num[k-1]+" ");
}
}
//合并完成之后需要将链表清空,否则元素会越来越多
list[i].clear();
}
System.out.println();
}
//将所有的元素分散到各个链表之中
public static void split(ArrayList<Integer> list[],int num[],int k) {
for(int j=0;j<num.length;j++) {
list[num[j]/k%10].add(num[j]);
}
System.out.println("-----------------------------------------------------------------------");
System.out.println("个位开始数,第"+(String.valueOf(k).length())+"位排序结果:");
for(int j=0;j<10;j++) {
System.out.println((String.valueOf(k).length())+"号位,数值为"+j+"的链表结果:"+list[j]);
}
}
public static void main(String[] args) {
ArrayList<Integer>list[]=new ArrayList [10];
for(int i=0;i<10;i++) {
list[i]=new ArrayList<Integer>();
}
int []num ={7,14,9,333,201,1,88,6,57,10,56,74,36,234,456};
long startTime=System.currentTimeMillis();
int max=Integer.MIN_VALUE;
//第一次遍历获得序列中的最大值
for(int i=0;i<num.length;i++) {
if(num[i]>max)
max=num[i];
}
int k=1;
for(int i=0;i<String.valueOf(max).length();i++) {
split(list, num, k);
System.out.println("第"+(i+1)+"次排序");
merge(list, num);
k=k*10;
}
long endTime=System.currentTimeMillis();
System.out.println("程序运行时间: "+(endTime-startTime)+"ms");
}
}
11.二维数组排序:
对于一个已定义的二位数组a经行如下规则排序,首先按照每一个对应的一维数组第一个元素进行升序排序(即a[][0]),若第一个元素相等,则按照第二个元素进行升序排序(a[][1])。(特别注意,这里的a[][0]或者a[][1]在java中是不能这么定义的,这里只是想说明是对于某一个一维数组的第0或1个元素进行排序)
import java.util.Arrays;
import java.util.Comparator;
public class Solution
{
public static void main(String[] args) {
int[][] nums=new int[][]{{1,3},{1,2},{4,5},{3,7}};
//方法一
/*Arrays.sort(nums,new Comparator<int[]>(){
public int compare(int[] a,int[] b){
if(a[1]==b[1]){
//若a[0] b[0]值相同则比较a[1] b[1],按升序
return a[0]-b[0];
}else{
return a[1]-b[1];
}
}
});
//方法二
*/Arrays.sort(nums,(a,b)->a[1]-b[1]);
for(int i=0;i<nums.length;i++){
System.out.println(Arrays.toString(nums[i]));
}
}
}
[1, 2]两个方法输出的结果是一样的
[1, 3]
[4, 5]
[3, 7]
排序力扣习题:
a[1]-b[1];
}
}
});
//方法二
*/Arrays.sort(nums,(a,b)->a[1]-b[1]);
for(int i=0;i<nums.length;i++){
System.out.println(Arrays.toString(nums[i]));
}
}
}
[1, 2]两个方法输出的结果是一样的
[1, 3]
[4, 5]
[3, 7]
## 排序力扣习题:
1.有效字母异位词:[](https://leetcode.cn/problems/valid-anagram/)
2.三位数之和:[](https://leetcode.cn/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/)
解答:[](https://blog.youkuaiyun.com/starflyyy/article/details/106955473)
3.三位数进阶:[](https://leetcode.cn/problems/3sum-closest/submissions/)