C语言中常用的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序。下面我们来一一介绍:
for
循环,所示它的时间复杂度是O(n^2)
。O(n^2)
。O(n^2)
。O(n^2)
,但是在平均情况下,快速排序的时间复杂度是O(n log n)
。O(n log n)
。O(n log n)
。总的来说,这些排序算法各有各的优点和适用场景,例如,冒泡排序、选择排序和插入排序适用于小规模数据或者部分有序数据,而快速排序、归并排序和堆排序通常适用于大规模数据排序。
#include
void bubbleSort(int arr[], int n)
{
int i, j;
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
void main(void)
{
int arr[] = {2, 5, 6, 9, 3, 8, 1, 4, 7};
bubbleSort(arr, sizeof(arr) / sizeof(arr[0]));
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
printf("%d", arr[i]);
}
由于冒泡排序算法过于简单,这里就不详细分析代码逻辑了,需要注意的是两层循环中循环次数的配置。
void selectionSort(int arr[], int n)
{
int i, j, minIndex, temp;
for (i = 0; i < n-1; i++) {
minIndex = i;
for (j = i+1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
}
void selectionsort(int arr[], int n)
:这是一个名为 selectionsort 的函数,它接受一个整型数组和一个整数作为参数。整型数组是要被排序的数据,整数代表数组的长度。int i, j, minindex, temp
; :声明四个整型变量,i和j用于循环遍历,minindex
用于保存当前最小元素的索引,temp
用于交换元素。for (i = 0; i < n-1; i++)
:外层循环,用于遍历数组。由于选择排序是每次从未排序元素中选择最小(或最大)的元素放到已排序序列的末尾,所以只需要遍历到倒数第二个元素,最后一个元素自然就是最大(或最小)的。minindex = i
; :将当前遍历的元素索引赋值给 minindex
,假设当前元素就是未排序元素中最小的。for (j = i+1; j < n; j++)
:内层循环,用于遍历i之后的所有元素,寻找真正的最小元素。if (arr[j] < arr[minindex])
:如果找到一个元素小于当前最小元素,就更新最小元素。minindex = j
; :将新的最小元素的索引赋值给 minindex
。temp = arr[minindex]; arr[minindex] = arr[i]; arr[i] = temp;
:交换当前遍历的元素(arr[i]
)和最小元素(arr[minindex]
),将最小元素放到已排序序列的末尾。通过以上的步骤,整个数组经过n-1
次遍历后,就会被排序完成。这就是选择排序的基本思想。
void insertionSort(int arr[], int n)
{
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
void insertionsort(int arr[], int n)
:这是一个名为insertionsort的函数,它接受一个整型数组和一个整数作为参数。整型数组是要被排序的数据,整数用于表示数组的长度。int i, key, j;
:声明并初始化三个整型变量,i
和j
用于循环遍历,key
用于保存当前要插入的元素。for (i = 1; i < n; i++)
:外层循环,用于遍历数组。由于插入排序的原理是将未排序的元素依次插入到已排序的数组中,因此从数组的第二个元素开始遍历。key = arr[i]
;:保存当前要插入的元素。j = i - 1
;:j 用于遍历已排序的数组,从最后一个已排序的元素开始。while (j >= 0 && arr[j] > key)
:内层循环,如果已排序的元素大于要插入的元素,就将已排序的元素向后移动。arr[j + 1] = arr[j]
;:将大于要插入元素的值向后移动。j = j - 1
;:移动到已排序数组的前一个元素。arr[j + 1] = key
;:当已排序的元素不大于要插入的元素或已经没有元素可以比较时,就将要插入的元素放到正确的位置。通过以上的步骤,整个数组经过n-1次遍历后,就会被排序完成。这就是插入排序的基本思想。
int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j <= high- 1; j++) {
if (arr[j] <= pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
return (i + 1);
}
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);
}
}
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for (i = 0; i < n1; i++) {
L[i] = arr[l + i];
}
for (j = 0; j < n2; j++) {
R[j] = arr[m + 1+ j];
}
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int arr[], int l, int r)
{
if (l < r) {
int m = l+(r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void heapify(int arr[], int n, int i)
{
int largest = i;
int l = 2*i + 1;
int r = 2*i + 2;
if (l < n && arr[l] > arr[largest]) {
largest = l;
}
if (r < n && arr[r] > arr[largest]) {
largest = r;
}
if (largest != i) {
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--) {
swap(&arr[0], &arr[i]);
heapify(arr, i, 0);
}
}
用某排序方法对一个关键码序列进行递增排序时,对于其中关键码相同的元素,若该方法可保证在排序前后这些元素的相对位置不变,则称该排序方法是稳定的。