package project12_2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @auther 张弢
* @create 2022-12-02 11:17
*/
public class Sort {
public static void main(String[] args) {
int[] arr={1,8,7,44,42,46,38,34,33,17,15,16,27,28,24};
// Sort.bubbleSort(arr);//冒泡
// Sort.selectSort(arr);//选择
// Sort.insertSort(arr);//插入
// Sort.shellSort(arr);//希尔
// Sort.quickSort(arr,0,14);//快速
// Sort.heapSort(arr);//堆
// Sort.mergeSort(arr,0,arr.length-1);//归并
// arr = Sort.CountSort(arr);//计数
// Sort.bucketSort(arr);//桶
// Sort.radixSort(arr);//基数
traverse(arr);//数组遍历
}
//遍历方法
public static void traverse(int[] arr){
for (int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
}
//1.冒泡排序
public static void bubbleSort(int[] arr){
for (int i=0;i<arr.length;i++){
for (int j=1;j<arr.length-i;j++){
if (arr[j-1] > arr[j]){
int temp =arr[j-1];
arr[j-1]=arr[j];
arr[j]=temp;
}
}
}
}
//2.选择排序
public static void selectSort(int[] arr){
for (int i=0;i<arr.length-1;i++){
int minIndex=i;
for (int j=i+1;j<arr.length;j++){
if (arr[j]< arr[minIndex]){
minIndex=j;//每次循环找到值最小的下标
}
}
int temp=arr[i];//每次循环结束后将最小值与数组第n(0-(length-1))位进行交换
arr[i]=arr[minIndex];
arr[minIndex]=temp;
}
}
//3.插入排序
public static void insertSort(int[] arr){
for (int i=1;i<arr.length;i++){
for (int j=i-1;j>=0;j--){
if (arr[j+1] < arr[j]){
int temp =arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
//4.希尔排序
public static void shellSort(int[] arr){
//初始化 划分增量
int increment = arr.length;
//每次循环减少增量,直到increment=1
while (increment >1){
//增量的多种取法之一
increment = increment/3 + 1;
//对每个按增量划分的分组分别进行 插入排序
for (int i=increment;i< arr.length;i++){
if (arr[i-increment] > arr[i]){
int temp = arr[i];//定义临时变量存放较小值
int j = i-increment;
//移动元素并寻找位置
while (j >= 0&& arr[j]>temp ){
arr[j+increment] = arr[j];//分组的后一个元素(较小值)被前一个元素(较大值)覆盖
j -= increment;//将前一个较小值与该组的前面的元素进行比较
}
//将较小值插入到正确的位置
arr[j+increment]= temp;
}
}
}
}
//5.快速排序
public static void quickSort(int [] arr,int left,int right){
//数组空则直接返回结束
if (left > right) return;
//查找基准元素
int mid= partition(arr,left,right);
//递归进行排序
quickSort(arr,left,mid-1);//将基准元素左边的区间进行快排
quickSort(arr,mid+1,right);//将基准元素右边的区间进行快排
}
private static int partition(int[] arr, int left, int right) {
//定义变量记录基准元素值
int basis = arr[left];
while (left < right){
//左、右指针交替循环移动
//右指针操作:right指针右向左扫描,扫描到数 《小于basis时,跳出循环,将小于基准的数赋值给相当于空余的基准位置赋值
while (arr[right]>=basis&&left<right) right--;
arr[left]=arr[right];
//左指针操作:left指针左向右扫描,扫描到数 《大于basis时,跳出循环,将大于基准的数赋值给相当于空余的基准位置赋值
while (arr[left]<=basis&&left<right) left++;
arr[right]=arr[left];
}
arr[left]=basis;//或arr[right]=basis
return left;
}
//6.堆排序
public static void heapSort(int[] arr) {
//旧数组构造==》符合大根堆的新数组
heapInsert(arr);
int size = arr.length;
while (size > 1) {
//固定最大值在数组的末索引,以构成有序
swap(arr, 0, size - 1);
size--;
//固定最大值将剩余数继续构造大根堆
heapify(arr, 0, size);
}
}
//构造大根堆(通过新插入的数上升)
public static void heapInsert(int[] arr) {
for (int i = 0; i < arr.length; i++) {
//当前插入的索引
int currentIndex = i;
//父结点索引
int fatherIndex = (currentIndex - 1) / 2;
//如果当前插入的值大于其父结点的值,则交换值,并且将索引指向父结点
//然后继续和上面的父结点值比较,直到不大于父结点,则退出循环
while (arr[currentIndex] > arr[fatherIndex]) {
//交换当前结点与父结点的值
swap(arr, currentIndex, fatherIndex);
//当前索引变为其父索引
currentIndex = fatherIndex;
//重新计算新当前索引的新父索引,当前值与其父值比较判断是否进入循环继续交换
//规则三:父结点索引:(i-1)/2(这里计算机中的除以2,省略掉小数)
fatherIndex = (currentIndex - 1) / 2;
}
}
}
//将剩余的数构造成大根堆(通过顶端的数下降)
public static void heapify(int[] arr, int index, int size) {
int left = 2 * index + 1;//规则一:寻找左孩子索引:2*i+1
int right = 2 * index + 2;规则二:寻找左孩子索引:2*i+2
//取左右孩子的最大值,并与其父节点的值比较判断是否交换值
while (left < size) {
int largestIndex;
//判断孩子中较大的值的索引(要确保右孩子在size范围之内)
if (arr[left] < arr[right] && right < size) {
largestIndex = right;
} else {
largestIndex = left;
}
//比较父结点的值与孩子中较大的值,并确定最大值的索引
if (arr[index] > arr[largestIndex]) largestIndex = index;
//如果父结点索引是最大值的索引,那已经是大根堆了,则退出循环
if (index == largestIndex) break;
//父结点不是最大值,与孩子中较大的值交换
swap(arr, largestIndex, index);
//将索引指向孩子中较大的值的索引
index = largestIndex;
//重新计算交换之后的孩子的索引
left = 2 * index + 1;
right = 2 * index + 2;
}
}
//交换数组中两个元素的值
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//7.归并排序
public static void mergeSort(int[] arr,int left,int right){
if (left == right) return;//left、right相遇即分解完成
int mid =(left+right)>>>1;//无符号右移一位,取中间值,相当于除2
mergeSort(arr,left,mid);//将左侧继递归分解
mergeSort(arr,mid+1,right);//将右侧递归分解
merge(arr,left,mid,right);// --将左右递归合并--合并为有序,
}
private static void merge(int[] arr, int left, int mid, int right) {
int s1= left;//左 归并段的开始位置
int s2=mid+1;//右 归并段的开始位置
//创建数组存放合并后的归并段
int[] res =new int[right-left+1];//(3-0)+1=4:两归并段之和
int i=0;//表示res数组的下标
//比较s1、s2谁小谁入数组,将左、右归并段合并为有序归并段
while (s1<=mid && s2<=right){//保证两个归并段都有数据
if(arr[s1] <=arr [s2]){
res[i++]=arr[s1++];
}else {
res[i++]=arr[s2++];
}
}
//可能左右字段还存在未拷贝值,以下再次判断,有值则继续拷贝完成
while (s1<=mid){
res[i++]=arr[s1++];
}
while (s2<=right){
res[i++]=arr[s2++];
}
//将res数组存的有序归并段放回原数组正确位置:加上left起始位置
for (int j=0;j<res.length;j++){
arr[j+left] = res[j];
}
}
//8.计数排序
public static int[] CountSort(int[] arr){
//①找出原数组中的最大值
int max=0;
for (int i=0;i<arr.length;i++){
if (arr[i]>max) max=arr[i];
}
//②初始化计数数组
int[] count=new int[max+1];//长度为原数组最大值max+1
//原数组的值转换为计数数组的下标,count数组元素值 随 遍历相同下标而自增+1
for(int num:arr){
count[num]++;
}
//③创建结果数组
int[] result=new int[arr.length];
//创建result数组的起始索引
int index=0;
//④遍历计数数组,将计数数组的索引下标 填充到 result数组中
for (int i=0;i<count.length;i++){
while (count[i]>0){
result[index++]=i;
count[i]--;
}
}
return result;
}
//9.桶排序
public static void bucketSort(int[] arr){
//计算最大值、最小值
int max=arr[0];
int min=arr[0];
for (int i=1;i<arr.length;i++){
if (arr[i] < min) min=arr[i];
if (arr[i] > max) max=arr[i];
}
//max-nin之差除数组长度,计算需桶数量
int bucketNum=(max-min)/arr.length+1;//(46-1)/15再+1等于4个桶
//创建桶,数量为bucketNum
List<ArrayList<Integer>> buckets=new ArrayList(bucketNum);
for (int i=0;i<bucketNum;i++){
buckets.add(new ArrayList());
}
//将每个元素放入对应的桶中
for (int i=0;i< arr.length;i++){
int num=(arr[i]-min)/arr.length;//找元素对应的桶,元素越小,对应桶下标越小
buckets.get(num).add(arr[i]);//放入对应的元素
}
//对桶中的元素进行排序
for (int i=0;i<buckets.size();i++){
Collections.sort(buckets.get(i));
}
//因为桶间已经有序,则逐一将桶中的元素赋值到原始数组
for (int i=0,index=0;i<buckets.size();i++){
for (int j=0;j<buckets.get(i).size();j++){
arr[index++]=buckets.get(i).get(j);
}
}
}
//10.基数排序
public static void radixSort(int[] arr){
//取得数组中最大值
int max=0;
for (int i=0;i<arr.length;i++){
if (arr[i] > max) max=arr[i];
}
//最大值是几位数
int maxLength=(max+"").length();
//定义一个二维数组模拟桶,每个桶即一维数组
int[][] bucket=new int[10][arr.length];//10个桶,每个大小为数组长度
//记录每个桶中实际存放的元素个数
int[] bucketElementCounts=new int[10];
//创建maxLength轮桶排序操作(对应个、十、百、...位的操作),就可将数组进行排序
for (int i=0,n=1;i<maxLength;i++,n=n*10){//n=1:个位 n=10:十位 n=100:百位,通过变量n取出元素位数上的数
for (int j=0;j<arr.length;j++){
int digitOfElement = arr[j]/n%10;//针对每个元素第n位数进行处理
bucket[digitOfElement][bucketElementCounts[digitOfElement]]=arr[j];//[桶][桶元素个数]=arr[j]
bucketElementCounts[digitOfElement]++;//桶里元素个数+1
}
//按照桶顺序取出数据并放回原数组
for (int k=0,index=0;k<bucket.length;k++){
if (bucketElementCounts[k]!=0){
for (int l=0;l<bucketElementCounts[k];l++){
arr[index++] = bucket[k][l];
}
}
bucketElementCounts[k]=0;
}
}
}
}
十大排序算法JAVA实现
于 2022-12-04 15:59:10 首次发布