排序
Posted sanweizuiji
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序相关的知识,希望对你有一定的参考价值。
1 排序
1.1 内排序、外排序
1.2 排序的稳定性
2 排序算法
#include <stdio.h>
// 共 46 个元素
#define arrSize 46
// 辅助数组,用来将 arr 复制一份保存到 tempArr 中
int tempArr[arrSize] = 0;
int main()
int arr[] = 123, 234, 3546, 1, 3, 5, 767, 8, 9, 78, 1,
214, 5, 6, 457, 8, 8, 5, 5, 2124, 5,
656688, 4, 4, 6, 541, 24, 412, 5, 6454, 68,
8, 979, 780870, 231, 1, 2, 4, 4, 54647, 56,
35, 23, 52, 3, 37;
// insertionSort(arr, arrSize);
// shellSort(arr, arrSize);
// bubbleSort(arr, arrSize);
// quickSort(arr, 0, arrSize);
// selectSort(arr, arrSize);
// heapSort(arr, arrSize - 1);
// mergeSort(arr, 0, arrSize - 1);
for (int i = 0; i < arrSize; i++)
printf("%d\\n", arr[i]);
2.1 直接插入排序
void insertionSort(int arr[], int size)
for (int i = 1; i < size; i++)
if (arr[i] < arr[i - 1])
int temp = arr[i];
// 检查所有前面已排好序的元素,将比 temp 大的元素后移,并将 temp 插入到合适位置
int j;
for (j = i - 1; j >= 0 && temp < arr[j]; j--)
arr[j + 1] = arr[j];
arr[j + 1] = temp;
空间复杂度
O
(
1
)
O(1)
O(1)
时间复杂度(主要来自对比关键字、移动元素)
最好情况(原本就有序):共n-1趟处理,每一趟只需要对比关键字1次,不用移动元素
O
(
n
)
O(n)
O(n)
最坏情况(原本为逆序):第 1 趟:对比关键字2次,移动元素3次;第 2 趟:对比关键字3次,移动元素4次;第 i 趟:对比关键字i+1次,移动元素i+2次
O
(
n
2
)
O(n^2)
O(n2)
平均时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
例 (插入排序)在链表中进行操作比在顺序表中进行操作效率高
2.2 Shell 排序(不稳定,划分子表后排序可能导致不稳定)
void shellSort(int arr[], int size)
// 步长初始化为数组长度的一半,每次遍历后步长减半
for (int gap = size / 2; gap > 0; gap /= 2)
// 变量 i 为每次分组的第一个元素下标
for (int i = 0; i < gap; i++)
// 对步长为 gap 的元素组进行直接插入排序
for (int j = i + gap; j < size; j = j + gap)
if (arr[j] < arr[j - gap])
int temp = arr[j];
// 检查所有前面已排好序的元素
int k;
for (k = j - gap; k >= 0 && temp < arr[k]; k = k - gap)
arr[k + gap] = arr[k];
arr[k + gap] = temp;
空间复杂度
O
(
1
)
O(1)
O(1)
时间复杂度
2.3 冒泡排序
void bubbleSort(int arr[], int size)
// 每趟都把最小的数移到最前面
for (int i = 0; i < size - 1; i++)
int flag = 0;
for (int j = size - 1; j > i; j--)
if (arr[j] < arr[j - 1])
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
flag = 1;
// 若这趟没有发生交换,说明剩余序列已经有序了
if (flag == 0)
break;
空间复杂度
O
(
1
)
O(1)
O(1)
时间复杂度
最好情况(原本有序):比较次数 n-1 次,flag 表明没有发生交换操作
O
(
n
)
O(n)
O(n)
最坏情况(原本逆序):
O
(
n
2
)
O(n^2)
O(n2)
平均时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
2.4 快速排序(不稳定,如对 2 2 1 进行排序,第一个 2 作为基准元素时会被移动到第三个位置)
// 用第一个元素将待排序的序列划分成左右两个部分
int partition(int arr[], int low, int high)
// 第一个元素作为基准
int pivot = arr[low];
// 用 low 和 high 搜索基准最终位置
while (low < high)
// high 一直左移,直到找到比基准小的数后停止循环
while (low < high && arr[high] >= pivot)
high--;
// 将找到的比基准小的数移动到左边
arr[low] = arr[high];
// low 一直右移,直到找到比基准大的数后停止循环
while (low < high && arr[low] <= pivot)
low++;
// 将找到的比基准大的数移动到右边
arr[high] = arr[low];
arr[low] = pivot;
// 返回基准元素存放的位置
return low;
void quickSort(int arr[], int low, int high)
if (low < high)
int pivotPos = partition(arr, low, high);
quickSort(arr, low, pivotPos - 1);
quickSort(arr, pivotPos + 1, high);
空间复杂度(递归层数 = 用基准元素划分生成的二叉树的深度)
最好情况:
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n)
最坏情况:
O
(
n
)
O(n)
O(n)
时间复杂度
最好情况:
O
(
n
∗
递归层数
)
=
O
(
n
∗
l
o
g
2
n
)
O(n*递归层数)=O(n*log_2n)
O(n∗递归层数)=O(n∗log2n)
最坏情况:
O
(
n
∗
递归层数
)
=
O
(
n
∗
n
)
=
O
(
n
2
)
O(n*递归层数)=O(n*n)=O(n^2)
O(n∗递归层数)=O(n∗n)=O(n2)
平均:
O
(
n
∗
递归层数
)
=
O
(
n
∗
l
o
g
2
n
)
O(n*递归层数)=O(n*log_2n)
O(n∗递归层数)=O(n∗log2n)
2.5 简单选择排序(不稳定,如对 2 2 1 进行排序)
void selectSort(int arr[], int arrSize)
for (int i = 0; i < arrSize - 1; i++)
// 记录最小元素的位置
int min = i;
// 在i+1-n中选择最小的元素
for (int j = i + 1; j < arrSize; j++)
if (arr[j] < arr[min])
// 更新最小元素位置
min = j;
// 如果发现更小的元素则与 arr[i] 交换
if (min != i)
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
空间复杂度
O
(
1
)
O(1)
O(1)
时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
2.6 堆排序(不稳定,如对 1 2 2 进行排序)
// fallingElement 为需要下坠的元素
void headAdjust(int arr[], int fallingElement, int len)
// arr[0] 保存本次要下坠的元素
arr[0] = arr[fallingElement];
for (int j = fallingElement * 2; j <= len; j = j * 2)
// 判断左右孩子的大小,调整 j
if (j < len && arr[j] < arr[j + 1])
j = j + 1;
// 如果本次下坠的元素大于左右孩子,那符合大根堆的要求,直接跳出下坠操作,如果不满足,则将较大的孩子结点移动到目前下坠元素的位置
if (arr[0] >= arr[j])
break;
else
arr[fallingElement] = arr[j];
fallingElement = j;
arr[fallingElement] = arr[0];
// 建立大根堆
void buildMaxHeap(int arr[], int len)
for (int i = len / 2; i > 0; i--)
headAdjust(arr, i, len);
// 堆排序(注意用 a[0] 是用来暂存元素的,len 是除 a[0] 以外的数组元素的个数)
void heapSort(int arr[], int len)
buildMaxHeap(arr, len);
for (int i = len; i > 1; i--)
// 交换已经构建好的大根堆的首尾元素
int temp = arr[i];
arr[i] = arr[1];
arr[1] = temp;
// 再将第一个元素下坠,并且最后一个元素已确定位置,故不在考虑范围之内
headAdjust(arr, 1, i - 1);
空间复杂度
O
(
1
)
O(1)
O(1)
时间复杂度
O
(
n
l
o
g
2
n
)
O(nlog_2n)
O(nlog2n)
例 堆排序是一种(选择)排序
2.7 归并排序
// arr[low,mid] 和 arr[mid+1,high] 各自有序,将两个部分归并
void merge(int arr[], int low, int mid, int high)
// 将 arr 中所有元素复制到 tempArr 中
for (int i = low; i <= high; i++)
tempArr[i] = arr[i];
int temp_i, temp_j, arr_k;
for (temp_i = low, temp_j = mid + 1, arr_k = low; temp_i <= mid && temp_j <= high; arr_k++)
if (tempArr[temp_i] <= tempArr[temp_j])
arr[arr_k] = tempArr[temp_i];
temp_i = temp_i + 1;
else
arr[arr_k] = tempArr[temp_j];
temp_j = temp_j + 1;
// 将剩余的元素也赋值到 arr 中
while (temp_i <= mid)
arr[arr_k] = tempArr[temp_i];
arr_k = arr_k + 1;
temp_i = temp_i + 1;
while (temp_j <以上是关于排序的主要内容,如果未能解决你的问题,请参考以下文章