//公共方法:交换位置
private static void exchangePosition(Integer[] arr, int index1, int index2){
int temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
//【冒泡排序】 和 【快速排序】 都属于 【交换排序】
//【冒泡排序】:每一次遍历,都把相邻的两个数中,大的那个数放到右侧,因此一次遍历结束后,最大的数已经放在了最右侧
public static void bubbleSort(Integer[] arr){
int size = arr.length;
boolean positionExchanged;
for (int maxValueIndex = size - 1; maxValueIndex >= 0; maxValueIndex --) {
positionExchanged = false;
for (int i = 0; i < maxValueIndex; i++) {
if(arr[i] > arr[i + 1]){
exchangePosition(arr, i, i + 1);
positionExchanged = true;
}
}
//如果一次遍历中没有发生位置交换,说明 a1 <= a2 <= ... <= an,则表明已经排序好了,无须继续下一轮的遍历
if(!positionExchanged){
break;
}
}
}
//【快速排序】
//1.对于数组 a[startIndex] ~ a[endIndex],随机选一个基准点base = a[x],把大于基准点的数放到基准点的右侧,把小于基准点的数放到基准点的左侧,
// 这样执行完一轮后,a[startIndex] ~ a[x-1] 的值都小于 base,a[x+1] ~ a[endIndex] 的值都大于 base
//2.对 a[startIndex] ~ a[x-1] 和 a[x+1] ~ a[endIndex] 递归执行上述逻辑
//3.递归执行结束后整个数组就是有序的了
public static void quickSort(Integer[] arr, int startIndex, int endIndex){
//递归退出的条件
if(startIndex >= endIndex){
return;
}
//选择第一个数为基准点
int base = arr[startIndex];
//把 startIndex 和 endIndex 赋值给 left 和 right 执行遍历,是因为遍历结束后还需要用到 startIndex 和 endIndex 的值
int left = startIndex;
int right = endIndex;
//本来遍历退出的条件
while(left < right){
//从右往左查找小于base的点
while (left < right && arr[right] >= base){
right --;
}
//left < right成立,说明 arr[right] < base
if(left < right){
arr[left] = arr[right];
left ++;
}
//从左往右查找大于base的点
while (left < right && arr[left] <= base){
left ++;
}
//left < right成立,说明 arr[left] > base
if(left < right){
arr[right] = arr[left];
right --;
}
}
//遍历结束后,left 对应的 arr[left] 的原始值已经赋值给其它点了,需要把 base,即一开始的起始点,赋值给 arr[left]
arr[left] = base;
quickSort(arr, startIndex, left - 1);
quickSort(arr, left + 1, endIndex);
}
//【直接插入排序】,【二分插入排序】和【希尔排序】,都是 【插入排序】
//【直接插入排序】:假定某个点之前部分的数组是有序的,把此点插入到有序的部分数组
public static void directlyInsertSort(Integer[] arr){
int size = arr.length;
int j, temp;
for (int i = 1; i < size; i++) {
temp = arr[i];
for (j = i - 1; j >= 0 ; j --) {
if(arr[j] > temp){
arr[j + 1] = arr[j];
}else {
break;
}
}
arr[j + 1] = temp;
}
}
//【希尔排序】
public static void shellSort(Integer[] arr){
int size = arr.length;
for (int step = size / 2; step >= 1 ; step /= 2) {
for (int loop = 0; loop < step; loop ++) {
int j, temp;
for (int i = loop + step; i < size; i += step) {
temp = arr[i];
for (j = i - step; j >= loop; j -= step) {
if(arr[j] > temp){
arr[j + step] = arr[j];
}else {
break;
}
}
arr[j + step] = temp;
}
}
}
}
//【简单选择排序】和【堆排序】,都是 【选择排序】
//【简单选择排序】:类似于冒泡排序;每次遍历找到最大值,遍历结束后把最大值放到数组最右侧
public static void simpleSelectSort(Integer[] arr){
int size = arr.length;
int index;
for (int maxValueIndex = size - 1; maxValueIndex > 0; maxValueIndex --) {
index = maxValueIndex;
for (int i = 0; i < maxValueIndex; i++) {
if(arr[i] > arr[index]){
index = i;
}
}
if(index != maxValueIndex){
exchangePosition(arr, maxValueIndex, index);
}
}
}
//【堆排序】:把数组看做堆,使得堆中每个父节点的值大于其子节点的值,堆准备完成后,把堆的根节点和数组的最右侧节点交换位置
public static void heapSort(Integer[] arr){
for (int heapSize = arr.length; heapSize > 1; heapSize --){
//创建堆:使任何一个节点的值大于左右子节点的值
//如果 parentNodeIndex > heapSize / 2,则其子节点的 index 肯定超出了 heapSize ,所以不必判断此情况
for (int parentNodeIndex = heapSize / 2; parentNodeIndex >= 0; parentNodeIndex --) {
makeParentNodeMax(arr, heapSize, parentNodeIndex);
}
//堆创建完成后,把最大值(index = 0)放到数组的最右侧(index = heapSize - 1)
exchangePosition(arr, 0, heapSize - 1);
}
}
//比较三个节点(一个父节点和两个子节点)的大小,把值大的放到父节点
private static void makeParentNodeMax(Integer[] arr, int heapSize, int parentNodeIndex){
int maxValueIndex = parentNodeIndex;
int leftChildNodeIndex = parentNodeIndex * 2 + 1;
int rightChildNodeIndex = parentNodeIndex * 2 + 2;
if(leftChildNodeIndex < heapSize){
if(arr[leftChildNodeIndex] > arr[maxValueIndex]){
maxValueIndex = leftChildNodeIndex;
}
}
if(rightChildNodeIndex < heapSize){
if(arr[rightChildNodeIndex] > arr[maxValueIndex]){
maxValueIndex = rightChildNodeIndex;
}
}
if(maxValueIndex != parentNodeIndex){
exchangePosition(arr, maxValueIndex, parentNodeIndex);
//如果发生了节点位置的交换,则需要对新交换的子节点及子节点的左右子节点进行值的比较和位置的交换
makeParentNodeMax(arr, heapSize, maxValueIndex);
}
}
//【归并排序】:两个有序数组合并为一个有序数组
//合并过程中,使用到了额外的内存空间来暂存数据
public static void mergeSort(Integer[] arr){
merge(arr, 0, arr.length - 1);
}
private static void merge(Integer[] arr, int leftIndex, int rightIndex){
if(leftIndex >= rightIndex){
return;
}
int middle = (leftIndex + rightIndex) / 2;
merge(arr, leftIndex, middle);
merge(arr, middle + 1, rightIndex);
int leftArrSize = middle - leftIndex + 1;
int[] leftArr = new int[leftArrSize];
int rightArrSize = rightIndex - (middle + 1) + 1;
int[] rightArr = new int[rightArrSize];
for (int i = 0; i < leftArrSize; i++) {
leftArr[i] = arr[i + leftIndex];
}
for (int i = 0; i < rightArrSize; i++) {
rightArr[i] = arr[i + middle + 1];
}
int i = 0, j = 0, k = leftIndex;
while(i < leftArrSize && j < rightArrSize){
if(leftArr[i] > rightArr[j]){
arr[k] = rightArr[j];
k ++;
j ++;
}else {
arr[k] = leftArr[i];
k ++;
i ++;
}
}
while (i < leftArrSize){
arr[k] = leftArr[i];
k ++;
i ++;
}
while (j < rightArrSize){
arr[k] = rightArr[j];
k ++;
j ++;
}
}
//【桶排序】:创建一个数组a1,其数组大小等于待排序数组a2的取值范围,把待排序数组的值(v=x)落到a1数组中去(k=x, v++),然后把a1数组中值不等于初始值(0)的点收集起来就是排序后的数组
//合并过程中,使用到了额外的内存空间来暂存数据
public static void bucketSort(Integer[] arr){
//找最大值 最小值
/*int max = 0, min = 0;
for (int value : arr){
if(max < value){
max = value;
}
if(min > value){
min = value;
}
}*/
//假定数组的取值范围是 [0, 100)
int max = 99;
int min = 0;
int size = arr.length;
int bucketSize = max - min + 1;
int[] bucket = new int[bucketSize];
for (int i = 0; i < size; i++) {
bucket[arr[i] - min] ++;
}
int count = 0;
for (int i = 0; i < bucketSize; i++) {
while (bucket[i] > 0){
arr[count] = i + min;
bucket[i] --;
count ++;
if(count >= size){
return;
}
}
}
}
//【基数排序】:对数组的个位数 十位数等n位数进行桶排序
public static void radixSort(Integer[] arr, int maxDigitLength){
int size = arr.length;
int[][] radix = new int[10][size];//radix[i][j] i = n位数的值,j = n位数值出现的频率-1 = i 出现的顺序
int[] frequency = new int[10];// frequency[k] k = i 出现的次数,j < k
int curDigit = 1;
int base = 1;
while (curDigit <= maxDigitLength) {
for (int j = 0; j < size; j++) {
int digitValue = (arr[j] / base) % 10;
radix[digitValue][frequency[digitValue]] = arr[j];
frequency[digitValue] ++;
}
int count = 0;
for (int digitValue = 0; digitValue <= 9; digitValue ++) {//外层对数字取值范围的循环,0-9
for (int frequencyAtCurDigitValue = 0; frequencyAtCurDigitValue < frequency[digitValue]; frequencyAtCurDigitValue ++) {//内层对同一个数字出现的次数进行循环
arr[count] = radix[digitValue][frequencyAtCurDigitValue];
count ++;
}
frequency[digitValue] = 0;
}
curDigit ++;
base *= 10;
}
}