class Sort{
//冒泡排序
public void Effervescence(int[] arr){
//核心思想是两两交换,每轮将最大的数交换到后面
for(int i = 0;i<arr.length-1;i++)
{
//每轮最大数放后面,j的边界变小
for(int j = 0;j<arr.length-1-i;j++)
{
if(arr[j]>arr[j+1])
{
//如果后面比前面小就交换
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
}
}
//选择排序
public static void Choose(int[] arr){
//核心思想是遍历找最小值,放在最前面,然后又从后面找
for(int i = 0;i<arr.length-1;i++)
{
int k = i;
int min = arr[i];
for(int j = i+1;j<arr.length;j++)
{
if(arr[j]<min)
{
min = arr[j];
k = j;
}
}
if(k != i)
{
int t = arr[i];
arr[i] = arr[k];
arr[k] = t;
}
}
}
//插入排序
public static void Insert(int[] arr){
//核心思想是将一个大小为n数组分为两表,前面有x个有序数后面有n-x个无序数
//从无序数里面找一个有序数插到有序数里面
for(int i = 1;i<arr.length;i++)
{
int val = arr[i];//获取当前值并保存
int index = i-1;//应该插入的下标
while(index>=0&&arr[index]>val)//直到该插入的位置的值比当前值小或越界则退出
{
arr[index+1] = arr[index];//将之前的值往后移
index--;
}
arr[index+1] = val;
}
}
//希尔排序_交换式
public static void Shell_Exchange(int[] arr){
//核心思想是在快排基础上进行优化
//将数组分组进行插入排序
//当步长gap<=0是退出
for(int gap = arr.length/2;gap>0;gap/=2)
{
//分组取步长
for(int i = gap;i<arr.length;i++)
{
for(int j = i-gap;j>=0;j-=gap)
{
if(arr[j]>arr[j+gap])
{
//shell交换式本质是冒泡
int t = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = t;
}
}
}
}
}
//希尔排序_移位式
public static void Shell_translocation(int[] arr){
//核心思想就是分组使用插入排序
for(int gap = arr.length/2;gap>0;gap/=2)
{
//分组
for(int i = gap;i<arr.length;i++)
{
int j = i;
int val = arr[i];
//保留当前值
if(val<arr[j-gap])
{
while(j-gap>=0&&val<arr[j-gap])
{
arr[j] = arr[j-gap];//移位
j-=gap;
}
arr[j] = val;//找到下标
}
}
}
}
//快速排序
public static void Quick(int[] arr,int low,int high){
//快排的核心思想是分治法
//选择一个支点将比该支点小的放左边,比支点大的放右边
//被分割为1,退出
if(low>=high)
return;
int prvot = arr[low];//选择第一个为支点
int l = low;//定义左右指针
int r = high;
while(l<r)
{
while(l<r&&prvot<=arr[r])
r--;
arr[l] = arr[r];//移步,插入排序思想
while(l<r&&prvot>=arr[l])
l++;
arr[r] = arr[l];
}
arr[l] = prvot;
Quick(arr,low,l-1);//递归,将左右两边排序
Quick(arr,r+1,high);
}
//归并排序
public static void Recursive_Merge(int[] arr,int low,int high,int[] temp){
//归并排序的思想也是分治法
//将一个大数组递归分成很多个小数组,将小数组排序后合并
if(low<high)
{
int mid = (low+high)/2;
Recursive_Merge(arr,low,mid,temp);//左边分
Recursive_Merge(arr,mid+1,high,temp);//右边分
Merge(arr,low,mid,high,temp);//合并治
}
}
public static void Merge(int[] arr,int low,int mid,int high,int[] temp){
int a = low;
int b = mid+1;//双指针
int index = low;
//开始合并两个有序数组
while(a<=mid&&b<=high)
{
if(arr[a]<=arr[b])
{
temp[index++] = arr[a++];
}
else
{
temp[index++] = arr[b++];
}
}
while(a<=mid)
temp[index++] = arr[a++];
while(b<=high)
temp[index++] = arr[b++];
//临时数组保存两个排序后的有序数组
for(int i = low;i<=high;i++)
{
arr[i] = temp[i];
}
}
//基数排序
public static void Radix(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();
//统计最大数位数,确定循环次数
int[][] bucket = new int[10][arr.length];//初始化十个桶
int[] bucketElementsCount = new int[10];//统计每个桶的元素个数
for(int t = 0;t<maxLength;t++)//总循环次数
{
for(int i = 0;i<arr.length;i++)
{
int num = arr[i]/(int)Math.pow(10,t)%10;//取得当前该位数
bucket[num][bucketElementsCount[num]++] = arr[i];//讲其对应数放在桶中
}
int index = 0;//原数组重新赋值,定义下标
for(int k = 0;k<bucketElementsCount.length;k++)
{
for(int l = 0;l<bucketElementsCount[k];l++)
{
arr[index++] = bucket[k][l];
}
bucketElementsCount[k] = 0;//桶元素个数指针重置
}
}
}
//堆排序
public static void Heap(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
int len = arr.length;
// 构建大顶堆,这里其实就是把待排序序列,变成一个大顶堆结构的数组
buildMaxHeap(arr, len);
// 交换堆顶和当前末尾的节点,重置大顶堆
for (int i = len - 1; i > 0; i--) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
len--;
heapify(arr, 0, len);
}
}
private static void buildMaxHeap(int[] arr, int len) {
// 从最后一个非叶节点开始向前遍历,调整节点性质,使之成为大顶堆
for (int i = (int)Math.floor(len / 2) - 1; i >= 0; i--) {
heapify(arr, i, len);
}
}
private static void heapify(int[] arr, int i, int len) {
// 先根据堆性质,找出它左右节点的索引
int left = 2 * i + 1;
int right = 2 * i + 2;
// 默认当前节点(父节点)是最大值。
int largestIndex = i;
if (left < len && arr[left] > arr[largestIndex]) {
// 如果有左节点,并且左节点的值更大,更新最大值的索引
largestIndex = left;
}
if (right < len && arr[right] > arr[largestIndex]) {
// 如果有右节点,并且右节点的值更大,更新最大值的索引
largestIndex = right;
}
if (largestIndex != i) {
// 如果最大值不是当前非叶子节点的值,那么就把当前节点和最大值的子节点值互换
int temp = arr[i];
arr[i] = arr[largestIndex];
arr[largestIndex] = temp;
// 因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整。
heapify(arr, largestIndex, len);
}
}
}
八大排序算法详解,java代码实现
于 2022-10-19 20:42:34 首次发布