冒泡排序(Bubble Sort)是最简单、最经典的排序算法之一。它的基本思想是重复地遍历要排序的列表,每次比较相邻的两个元素,如果顺序不正确则交换它们。冒泡排序的时间复杂度最好、最坏和平均情况下都为O(n^2),空间复杂度为O(1)。
void bubbleSort(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (nums[j] > nums[j + 1]) {
swap(nums[j], nums[j + 1]);
}
}
}
}
选择排序(Selection Sort)每次从未排序的列表中选择最小(或最大)的元素,然后将其放置在已排序列表的末尾。选择排序的时间复杂度也是O(n^2),空间复杂度为O(1)。
void selectionSort(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (nums[j] < nums[minIndex]) {
minIndex = j;
}
}
swap(nums[i], nums[minIndex]);
}
}
插入排序(Insertion Sort)将列表分为已排序和未排序两部分,每次从未排序部分选择一个元素插入到已排序部分的合适位置。插入排序的时间复杂度最好情况下为O(n),最坏和平均情况下为O(n^2),空间复杂度为O(1)。
void insertionSort(vector<int>& nums) {
int n = nums.size();
for (int i = 1; i < n; i++) {
int key = nums[i];
int j = i - 1;
while (j >= 0 && nums[j] > key) {
nums[j + 1] = nums[j];
j--;
}
nums[j + 1] = key;
}
}
希尔排序(Shell Sort)是对插入排序的一种改进,它将列表分成几个子列表进行插入排序,每次逐步缩小子列表的长度。希尔排序的时间复杂度依赖于所选用的间隔序列,最坏情况下为O(n^2),平均情况下为O(n log n),空间复杂度为O(1)。
void shellSort(vector<int>& nums) {
int n = nums.size();
for (int gap = n / 2; gap > 0; gap /= 2) {
for(int i = gap; i < n; i++) {
int temp = nums[i];
int j;
for(j = i; j >= gap && nums[j - gap] > temp; j -= gap) {
nums[j] = nums[j - gap];
}
nums[j] = temp;
}
}
}
归并排序(Merge Sort)采用分而治之的策略,将列表逐步分成较小的子列表,然后通过合并这些子列表来完成排序。归并排序的时间复杂度在任何情况下都是O(n log n),空间复杂度为O(n)。
void merge(vector<int>& nums, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
vector<int> L(n1), R(n2);
for (int i = 0; i < n1; i++) {
L[i] = nums[left + i];
}
for (int j = 0; j < n2; j++) {
R[j] = nums[mid + 1 + j];
}
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
nums[k] = L[i++];
} else {
nums[k] = R[j++];
}
k++;
}
while (i < n1) {
nums[k++] = L[i++];
}
while (j < n2) {
nums[k++] = R[j++];
}
}
void mergeSort(vector<int>& nums, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
merge(nums, left, mid, right);
}
}
快速排序(Quick Sort)也是一种分而治之的排序算法,通过选择一个基准值,将列表分为小于基准值和大于基准值的两部分,然后再对这两部分分别进行快速排序。快速排序的时间复杂度最好情况下为O(n log n),最坏情况下为O(n^2),平均情况下为O(n log n)。空间复杂度为O(1)。
int partition(vector<int>& nums, int low, int high) {
int pivot = nums[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (nums[j] < pivot) {
i++;
swap(nums[i], nums[j]);
}
}
swap(nums[i + 1], nums[high]);
return i + 1;
}
void quickSort(vector<int>& nums, int low, int high) {
if (low < high) {
int pivotIndex = partition(nums, low, high);
quickSort(nums, low, pivotIndex - 1);
quickSort(nums, pivotIndex + 1, high);
}
}
堆排序(Heap Sort)利用堆这种数据结构进行排序,首先构建一个最大(或最小)堆,然后依次将堆顶元素与列表末尾的元素交换并重新调整堆。堆排序的时间复杂度为O(n log n),空间复杂度为O(1)。
void heapify(vector<int>& nums, int n, int i) {
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && nums[left] > nums[largest]) {
largest = left;
}
if (right < n && nums[right] > nums[largest]) {
largest = right;
}
if (largest != i) {
swap(nums[i], nums[largest]);
heapify(nums, n, largest);
}
}
void heapSort(vector<int>& nums) {
int n = nums.size();
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(nums, n, i);
}
for (int i = n - 1; i > 0; i--) {
swap(nums[0], nums[i]);
heapify(nums, i, 0);
}
}
基数排序(Counting Sort)是一种非比较性的排序算法,根据每个元素的出现次数进行排序。它的时间复杂度为O(n + k),其中n是列表的长度,k是列表中的最大值。空间复杂度为O(n + k)。
以上就是八大排序算法的讲解以及它们的时间复杂度和空间复杂度。希望对您有所帮助!如有其他问题,请随时提问