一些经典的排序算法
关于排序算法相信各位同学都不陌生吧,从最基础的冒泡排序,快速排序,归并排序等,都是在算法面试中经常出现的问题,下面是对一些常见的排序算法进行的coding
比较排序
冒泡排序
重复地走访过要排序的数列,每次比较相邻两个元素,如果它们的顺序错误就把它们交换过来,越大的元素会经由交换慢慢“浮”到数列的尾端。
- java版本
public void bubbleSort(int[] arr) {
int temp = 0;
boolean swap;
for (int i = arr.length - 1; i > 0; i--) { // 每次需要排序的长度
// 增加一个swap的标志,当前一轮没有进行交换时,说明数组已经有序
swap = false;
for (int j = 0; j < i; j++) { // 从第一个元素到第i个元素
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swap = true;
}
}
if (!swap){
break;
}
}
}
- kotlin版本
fun bubbleSort(array: IntArray) {
var temp = 0
var swap: Boolean
for (i in array.size - 1 downTo 0) { //需要排序的序列
swap = false
for (j in 0..i) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1]
array[j + 1] = temp
swap = true
}
}
if (!swap) {
break
}
}
}
- 演示如下
归并排序
分解待排序的数组成两个各具 n/2 个元素的子数组,递归调用归并排序两个子数组,合并两个已排序的子数组成一个已排序的数组。
- Java版本
public void mergeSort(int[] arr) {
int[] temp = new int[arr.length];
internalMergeSort(arr, temp, 0, arr.length - 1);
}
private void internalMergeSort(int[] arr, int[] temp, int left, int right) {
// 当left == right时,不需要再划分
if (left < right) {
int mid = (left + right) / 2;
internalMergeSort(arr, temp, left, mid);
internalMergeSort(arr, temp, mid + 1, right);
mergeSortedArray(arr, temp, left, mid, right);
}
}
// 合并两个有序子序列
public void mergeSortedArray(int[] arr, int[] temp, int left, int mid, int right) {
int i = left;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= right) {
temp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
// 把temp数据复制回原数组
for (i = 0; i < k; i++) {
arr[left + i] = temp[i];
}
}
- Kotlin版本
fun mergeSort(array: IntArray) {
val temp = IntArray(array.size)
internalMergeSort(array, temp, 0, array.size - 1)
}
private fun internalMergeSort(array: IntArray, temp: IntArray, left: Int, right: Int) {
if (left < right) {
val mid = (left + right) / 2
internalMergeSort(array, temp, left, mid) //左边
internalMergeSort(array, temp, mid + 1, right) //右边
mergeSorted(array, temp, left, mid, right)
}
}
//合并两个有序子序列
private fun mergeSorted(array: IntArray, temp: IntArray, left: Int, mid: Int, right: Int) {
var i = left //左 [left,mid]
var j = mid + 1 //右[mid+1,right]
var k = 0
while (i <= mid && j <= right) {
temp[k++] = if (array[i] < array[j]) {
array[i++]
} else {
array[j++]
}
}
while (i <= mid) {
temp[k++] = array[i++]
}
while (j <= right) {
temp[k++] = array[j++]
}
// 把temp数据复制回原数组
for (i in 0 until k) {
array[left + i] = temp[i]
}
}
- 演示如下
快速排序
在待排序的数组选取一个元素作为基准,将待排序的元素进行分区,比基准元素大的元素放在一边,比其小的放另一边,递归调用快速排序对两边的元素排序。选取基准元素并分区的过程采用双指针左右交换。
- Java版本
public void quickSort(int[] arr){
quickSort(arr, 0, arr.length-1);
}
private void quickSort(int[] arr, int low, int high){
if (low >= high)
return;
int pivot = partition(arr, low, high); //将数组分为两部分
quickSort(arr, low, pivot - 1); //递归排序左子数组
quickSort(arr, pivot + 1, high); //递归排序右子数组
}
private int partition(int[] arr, int low, int high){
int pivot = arr[low]; //基准
while (low < high){
while (low < high && arr[high] >= pivot) {
high--;
}
arr[low] = arr[high]; //交换比基准大的记录到左端
while (low < high && arr[low] <= pivot) {
low++;
}
arr[high] = arr[low]; //交换比基准小的记录到右端
}
//扫描完成,基准到位
arr[low] = pivot;
//返回的是基准的位置
return low;
}
- Kotlin版本
fun quickSort(array: IntArray) {
quickSort(array, 0, array.size - 1)
}
private fun quickSort(array: IntArray, low: Int, high: Int) {
if (low <= high)
return
partition(array, low, high)
}
private fun partition(array: IntArray, low: Int, high: Int): Int {
val pivot = array[low]
var low = low
var high = high
while (low < high) {
while (low < high && array[high] >= pivot) {
high--
}
array[low] = array[high] //交换比基准大的记录到左端
while (low < high && array[low] <= pivot) {
low++
}
array[high] = array[low] //交换比基准小的记录到右端
}
//扫描完成
array[low] = pivot
//基准到位
return low
}
- 演示版本
线性排序
计数排序
根据待排序的数组中最大和最小的元素,统计数组中每个值为i的元素出现的次数,存入数组C的第i项,对所有的计数累加,然后反向填充目标数组。
- Java版本
public void countSort(int[] arr) {
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i = 0; i < arr.length; i++){
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
int[] b = new int[arr.length]; // 存储数组
int[] count = new int[max - min + 1]; // 计数数组
for (int num = min; num <= max; num++) {
// 初始化各元素值为0,数组下标从0开始因此减min
count[num - min] = 0;
}
for (int i = 0; i < arr.length; i++) {
int num = arr[i];
count[num - min]++; // 每出现一个值,计数数组对应元素的值+1
// 此时count[i]表示数值等于i的元素的个数
}
for (int i = min + 1; i <= max; i++) {
count[i - min] += count[i - min - 1];
// 此时count[i]表示数值<=i的元素的个数
}
for (int i = 0; i < arr.length; i++) {
int num = arr[i]; // 原数组第i位的值
int index = count[num - min] - 1; //加总数组中对应元素的下标
b[index] = num; // 将该值存入存储数组对应下标中
count[num - min]--; // 加总数组中,该值的总和减少1。
}
// 将存储数组的值替换给原数组
for(int i=0; i < arr.length;i++){
arr[i] = b[i];
}
}
- Kotlin版本
fun countSort(array: IntArray) {
var max = Int.MIN_VALUE
var min = Int.MAX_VALUE
for (i in array.indices) {
max = max.coerceAtLeast(array[i])
min = min.coerceAtMost(array[i])
}
val b = IntArray(array.size) // 存储数组
val count = IntArray(max - min + 1) // 计数数组
for (num in min..max) {
// 初始化各元素值为0,数组下标从0开始因此减min
count[num - min] = 0
}
for (i in array.indices) {
val num: Int = array[i]
count[num - min]++ // 每出现一个值,计数数组对应元素的值+1
// 此时count[i]表示数值等于i的元素的个数
}
for (i in min + 1..max) {
count[i - min] += count[i - min - 1]
// 此时count[i]表示数值<=i的元素的个数
}
for (i in array.indices) {
val num: Int = array[i] // 原数组第i位的值
val index = count[num - min] - 1 //加总数组中对应元素的下标
b[index] = num // 将该值存入存储数组对应下标中
count[num - min]-- // 加总数组中,该值的总和减少1。
}
// 将存储数组的值替换给原数组
for (i in array.indices) {
array[i] = b[i]
}
}
- 演示图
桶排序
找出待排序数组中的最大值max、最小值min,数组ArrayList作为桶,桶里放的元素用ArrayList存储。计算每个元素 arr[i] 放的桶,每个桶各自排序,遍历桶数组,把排序好的元素放进输出数组。
- Java版本
public static void bucketSort(int[] arr){
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i = 0; i < arr.length; i++){
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
// 桶数
int bucketNum = (max - min) / arr.length + 1;
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
for(int i = 0; i < bucketNum; i++){
bucketArr.add(new ArrayList<Integer>());
}
// 将每个元素放入桶
for(int i = 0; i < arr.length; i++){
int num = (arr[i] - min) / (arr.length);
bucketArr.get(num).add(arr[i]);
}
// 对每个桶进行排序
for(int i = 0; i < bucketArr.size(); i++){
Collections.sort(bucketArr.get(i));
for (int j = 0; j < bucketArr.get(i).size(); j++) {
arr[j] = bucketArr.get(i).get(j);
}
}
}
- Kotlin版本
fun bucketSort(arr: IntArray) {
var max = Int.MIN_VALUE
var min = Int.MAX_VALUE
for (i in arr.indices) {
max = max.coerceAtLeast(arr[i]) //最大值
min = min.coerceAtMost(arr[i]) //最小值
}
// 桶数
val bucketNum = (max - min) / arr.size + 1
val bucketArr: ArrayList<ArrayList<Int>> = ArrayList(bucketNum)
for (i in 0 until bucketNum) {
bucketArr.add(ArrayList())
}
// 将每个元素放入桶
for (i in arr.indices) {
val num = (arr[i] - min) / arr.size
bucketArr[num].add(arr[i])
}
// 对每个桶进行排序
for (i in 0 until bucketArr.size) {
bucketArr[i].sort()
for (j in 0 until bucketArr[i].size) {
arr[j] = bucketArr[i][j]
}
}
}