常见排序算法详解(C++实现)
排序算法是计算机科学中的基础技术,用于将数据序列按特定顺序(如升序或降序)排列。常见算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序和堆排序等。每种算法都有其原理、时间复杂度和适用场景。本文将逐一介绍这些算法,并提供C++代码实现,帮助你直观理解。
1. 冒泡排序(Bubble Sort)
冒泡排序通过重复比较相邻元素并交换顺序错误的元素,将最大元素逐渐"冒泡"到末尾。
- 原理:从数组开头开始,比较相邻元素,如果顺序错误则交换。重复此过程直到数组有序。
- 时间复杂度:平均和最坏情况为O(n\^2),最好情况(已有序)为O(n)。
- C++代码:
cpp
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
std::swap(arr[j], arr[j+1]);
}
}
}
}
2. 选择排序(Selection Sort)
选择排序通过重复选择未排序部分的最小元素,并将其放到已排序部分的末尾。
- 原理:遍历数组,找到最小元素,与当前位置交换。重复此过程直到数组有序。
- 时间复杂度:平均、最坏和最好情况均为O(n\^2)。
- C++代码:
cpp
void selectionSort(int arr[], int n) {
for (int i = 0; i < n-1; i++) {
int min_idx = i;
for (int j = i+1; j < n; j++) {
if (arr[j] < arr[min_idx]) {
min_idx = j;
}
}
std::swap(arr[i], arr[min_idx]);
}
}
3. 插入排序(Insertion Sort)
插入排序通过构建有序序列,对未排序元素逐个插入到正确位置。
- 原理:从第二个元素开始,将其与已排序部分比较,插入到合适位置。
- 时间复杂度:平均和最坏情况为O(n\^2),最好情况(已有序)为O(n)。
- C++代码:
cpp
void insertionSort(int arr[], int n) {
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i-1;
while (j >= 0 && arr[j] > key) {
arr[j+1] = arr[j];
j--;
}
arr[j+1] = key;
}
}
4. 快速排序(Quick Sort)
快速排序通过分治法选择基准元素,将数组分为小于基准和大于基准的两部分,递归排序。
- 原理:选择基准(如第一个元素),分区后递归排序子数组。
- 时间复杂度:平均和最好情况为O(n \\log n),最坏情况(已有序)为O(n\^2)。
- C++代码:
cpp
int partition(int arr[], int low, int high) {
int pivot = arr[low];
int i = low, j = high;
while (i < j) {
while (i < j && arr[j] >= pivot) j--;
if (i < j) arr[i++] = arr[j];
while (i < j && arr[i] <= pivot) i++;
if (i < j) arr[j--] = arr[i];
}
arr[i] = pivot;
return i;
}
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi-1);
quickSort(arr, pi+1, high);
}
}
5. 归并排序(Merge Sort)
归并排序使用分治法将数组分成两半,递归排序后合并。
- 原理:递归分割数组到最小单位,然后合并两个有序数组。
- 时间复杂度:平均、最坏和最好情况均为O(n \\log n)。
- C++代码:
cpp
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int L[n1], R[n2];
for (int i = 0; i < n1; i++) L[i] = arr[left+i];
for (int j = 0; j < n2; j++) R[j] = arr[mid+1+j];
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
}
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid+1, right);
merge(arr, left, mid, right);
}
}
6. 堆排序(Heap Sort)
堆排序利用堆数据结构,将数组视为最大堆,重复提取最大元素并调整堆。
- 原理:构建最大堆,交换根节点与末尾元素,调整堆大小并重复。
- 时间复杂度:平均、最坏和最好情况均为O(n \\log n)。
- C++代码:
cpp
void heapify(int arr[], int n, int i) {
int largest = i;
int left = 2*i + 1;
int right = 2*i + 2;
if (left < n && arr[left] > arr[largest]) largest = left;
if (right < n && arr[right] > arr[largest]) largest = right;
if (largest != i) {
std::swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(int arr[], int n) {
for (int i = n/2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
for (int i = n-1; i > 0; i--) {
std::swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
总结
常见排序算法各有特点:
- 时间复杂度比较 :
- O(n\^2)算法:冒泡、选择、插入排序,简单但效率低,适合小规模数据。
- O(n \\log n)算法:快速、归并、堆排序,高效,适合大规模数据。
- 稳定性:冒泡、插入、归并排序是稳定的(相等元素顺序不变);选择、快速、堆排序不稳定。
- 空间复杂度:冒泡、选择、插入、堆排序为O(1);快速排序平均O(\\log n)(递归栈);归并排序为O(n)。
在实际应用中,选择算法需考虑数据规模、内存限制和稳定性需求。例如,快速排序在平均情况下性能优异,而归并排序适合外部排序。通过以上C++代码,你可以动手实现并加深理解。