class Sort {
/**
* 排序算法之冒泡排序
* @author 赵庚东
* 时间复杂度:O(N^2)
* 空间复杂度:O(1)
* 稳定性:稳定排序
* 大概思路:如果有N个元素将要进行比较大小,进行N-1次循环,每次循环找出当前部分中最大的数放到
* 该部分最后。
*/
public static void bubble(int[] arr,int size) {
if(size <= 1) {
return;
}
//遍历N-1次
for(int i = 0;i < size - 1;i++) {
//每次只需比较未排序部分
for(int j = 0;j < size - i - 1;j++) {
//如果后面的元素比当前元素小,将当前元素与后一个元素进行交换
if(arr[j] > arr[j + 1]) {
MyMethod.swap(arr, j, j + 1);
}
}
}
}
/**
* 排序算法之选择排序
* @author 赵庚东
* 时间复杂度:O(N^2)
* 空间复杂度:O(1)
* 稳定性:不稳定排序
* 大概思路:存在一个有序区间【0,bound)和一个无序区间【bound,size)
* 每次便利无序区间,从中找到一个最小的 值,放到当前bound处
* arr【bound】作为擂台
*/
public static void select (int[] arr,int size) {
if(size <= 1) {
return;
}
int bound = 0;
for(;bound < size;bound++) {
int cur = bound;
//在无序区间中找出最小元素
for(;cur < size;cur++) {
if(arr[cur] < arr[bound]) {
// cur 位置处的数比bound处的数小,
// 那么cur处的那个数占领擂台,
// 我们始终要让bound处的数为最小值
// 所以将cur处与bound处的数进行交换,使得bound处的数为最小值。
MyMethod.swap(arr, cur, bound);
}
}
}
return;
}
/**
* 排序算法之插入排序
* @author 赵庚东
* 大概思路:有一个有序区间【0,bound)和无序区间【bound,size)
* 每一次将bound处的数字插入到前面的有序区间当中
* 时间复杂度:O(N^2)
* 空间复杂度:O(1)
* 稳定排序
*/
public static void insert(int[] arr,int size) {
if(size <= 1) {
return;
}
int bound = 1;
for(;bound < size;bound++) {
int boundVal = arr[bound];
int i = bound;
for(;i > 0;i--) {
if(arr[i - 1] > boundVal) {
//如果bound前面的数字比bound处的数字大,就开始进行搬运
arr[i] = arr[i - 1];
}else {
//已经给boundVal找到一个合理的位置
//当前数组的这个元素已经小于boundVal,将boundVal直接放到arr【i】处
//arr[i] = boundVal;
break;
}
}
//循环执行完毕有两种情况:①、上面循环已经为boundVal找到合适的位置,②、一直没有找到合适位置,但是循环已经结束
//第二种情况其实就是boundVal是有序区间里最小的元素。
arr[i] = boundVal;
}
}
/**
* 排序算法之堆排序
* 升序建大堆,降序建小堆
* @author 赵庚东
* 大概思路:建大堆->循环删除堆顶元素,将堆顶元素与当前数组的最后一个元素进行交换->再进行向下调整
*/
public static void Heap(int[] arr,int size) {
if(size <= 1) {
return;
}
//1、建堆
HeapCreate(arr,size);
//2、循环删除堆顶元素
int i = 0;
for(;i < size; i++) {
heapPop(arr,size - i);
}
}
public static void HeapCreate(int[] arr,int size) {
if(size <= 1) {
return;
}
//向下调整:需要从后往前遍历
//从最后一个非叶子节点开始遍历
//size - 1表示最后一个元素的下标
//拿着这个下表 -1 / 2,就找到了当前元素的父节点
int i = (size - 1 - 1) / 2;
for(;i > 0;i--) {
adJustDown(arr, size, i);
}
}
//下面方法创建一个大堆:要求左右子树小于父节点
//index表示从当前下标开始向下调整
public static void adJustDown(int[] arr,int size,int index) {
int parent = index;
int child = 2 * parent + 1;//左子树
while(child < size) {
//先拿左右字数进行比较,看谁比较大,然后再拿大的跟父节点进行比较
if(child + 1< size && arr[child + 1] > arr[child]) {
child += 1;//child为当前父节点的右子树
}
//child处的值为当前父节点左右孩子中最大的
if(arr[child] > arr[parent]) {
MyMethod.swap(arr, child, parent);
}else {
break;
}
parent = child;
child = 2 * parent + 1;
}
return;
}
//循环删除操作先将当前堆顶元素与当前数组最后一个元素进行交换,然后再进行向下调整。
public static void heapPop(int[] arr,int size) {
if(size <= 1) {
return;
}
MyMethod.swap(arr, 0, size - 1);
adJustDown(arr, size - 1, 0);
}
/**
* 排序算法之快速排序
* @author 赵庚东
* 大概思路:找一个基准值,将当前数组中每一个元素与这个基准值相比
* 比基准值小的全部放到基准值左边,比基准值大的全部放到基准值右边
* 每次返回这个基准值的下标,然后对左右两边继续进行上述操作
* 平均时间复杂度:O(nlogn)
* 最差时间复杂度:O(n^2)
* 平均空间复杂度:O(logn)
* 最差空间复杂度:O(n)
* 不稳定排序
*/
//left表示当前数组需要被调整部分的第一个元素,right表示当前数组需要被调整部分的最后一个元素
public static void quick(int[] arr,int left,int right) {
if(left >= right) {
return;
}
int pivotIndex = partition(arr, left, right);//基准值所在下标
quick(arr, left, pivotIndex - 1);//对基准值左边进行处理
quick(arr, pivotIndex + 1, right);//对基准值右边进行处理
}
public static int partition(int[] arr,int left,int right) {
int pivot = arr[right];//将当前数组的最右边当作基准值
int tail = left - 1; //tail表示小于基准值那部分的最后一个元素
for(int i = 0;i < right;i++) {
if(arr[i] <= pivot) {
MyMethod.swap(arr, ++tail, i);//将数组中小于基准值的数与tail+1处的数进行交换,对tail自增
}
}
MyMethod.swap(arr, tail + 1, right);//将基准值与第一个比基准值大的书进行交换
return tail + 1;//返回基准值所在下标
}
}
class MyMethod {
public static void swap(int arr[],int x,int y) {
int c = arr[x];
arr[x] = arr[y];
arr[y] = c;
}
}
后续还会带来其它排序算法!