这是我参与「第五届青训营 」伴学笔记创作活动的第 17 天
快速排序
快速排序是一种基于比较的排序算法,它的基本思想是通过一次排序将待排序的元素分为两个部分,一部分小于某个值(称为pivot),一部分大于等于pivot。然后对这两个部分分别进行递归排序,直到整个序列有序。
func quickSort(arr []int, left, right int) {
if left >= right {
return
}
// 选择pivot
pivot := arr[left]
i, j := left, right
for i < j {
// 从右边开始找第一个小于pivot的元素
for i < j && arr[j] >= pivot {
j--
}
// 从左边开始找第一个大于pivot的元素
for i < j && arr[i] < pivot {
i++
}
// 交换arr[i]和arr[j]的位置
arr[i], arr[j] = arr[j], arr[i]
}
// 将pivot放在正确的位置上
arr[left], arr[i] = arr[i], arr[left]
// 对左右两个部分分别进行递归排序
quickSort(arr, left, i-1)
quickSort(arr, i+1, right)
}
在这个实现中,我们首先定义一个快速排序函数,它接受一个数组和两个整数left和right,表示排序的区间范围。如果left>=right,说明数组已经有序,可以直接返回。否则,我们选择数组的第一个元素作为pivot,然后使用两个指针i和j来分别指向数组的左右两端。然后,我们让j从右端开始向左移动,直到找到第一个小于pivot的元素;让i从左端开始向右移动,直到找到第一个大于等于pivot的元素。然后交换arr[i]和arr[j]的位置,继续移动i和j,直到i>=j为止。最后,我们将pivot放在正确的位置上,这里使用了交换arr[left]和arr[i]的位置来实现。然后,我们分别对左右两个部分进行递归排序。
快速排序的时间复杂度为O(nlogn),其中n是待排序的元素个数。快速排序是一种不稳定的排序算法。它通常比其他基于比较的排序算法更快,但是它的性能高度依赖于选择的pivot,如果pivot的选择不当,可能会导致算法的性能降低。
归并排序
归并排序是一种基于分治思想的排序算法,它将待排序的序列分为两个子序列,分别进行递归排序,最后将两个有序子序列合并成一个有序序列。归并排序的基本思想可以概括为“分而治之,然后合并”。
func mergeSort(arr []int) []int {
if len(arr) <= 1 {
return arr
}
// 将数组分为两个部分
mid := len(arr) / 2
left := mergeSort(arr[:mid])
right := mergeSort(arr[mid:])
// 合并两个有序子序列
return merge(left, right)
}
func merge(left, right []int) []int {
result := make([]int, 0, len(left)+len(right))
i, j := 0, 0
for i < len(left) && j < len(right) {
if left[i] <= right[j] {
result = append(result, left[i])
i++
} else {
result = append(result, right[j])
j++
}
}
result = append(result, left[i:]...)
result = append(result, right[j:]...)
return result
}
在这个实现中,我们首先定义一个归并排序函数,它接受一个数组作为参数。如果数组的长度小于等于1,说明数组已经有序,可以直接返回。否则,我们将数组分为两个部分,分别对左右两个部分进行递归排序。然后,我们调用merge函数将两个有序子序列合并成一个有序序列。merge函数接受两个有序子序列作为参数,返回一个合并后的有序序列。在merge函数中,我们定义一个result数组来保存合并后的有序序列。我们使用两个指针i和j来分别指向左右两个有序子序列的开头,比较left[i]和right[j]的大小,将较小的元素放入result数组中。然后,我们继续移动i和j,直到i或j超出数组范围为止。最后,我们将剩余的元素依次放入result数组中,返回result数组。
归并排序的时间复杂度为O(nlogn),其中n是待排序的元素个数。归并排序是一种稳定的排序算法,它的性能不受输入数据的影响。