记录排序的知识,也在后面不断学习的过程之中不断丰富该类算法,同样自己也把这里作为自己的笔记进行记录;这里也会详细介绍思想。
科普
什么是排序算法
所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
什么是算法稳定性
排序算法的稳定性是指在待排序序列中,若存在两个相等的元素,排序后这两个元素的相对位置是否会发生变化。如果相等元素的相对位置在排序后仍然保持不变,那么这样的排序算法被认为是稳定的;如果相对位置产生改变,则被认为该算法不稳定。
如何判断算法是否稳定
要判断一个排序算法是否稳定,可以通过分析该算法的特性来确定。对于不稳定的排序算法,只需要举出一个实例,即可说明它的不稳定性;而对于稳定的排序算法,必须深入分析算法以得出其稳定性。
冒泡排序
冒泡排序是一种计算机领域的简单的排序算法(也是最为基础的一种),在面临时间要求的时候可能会出现超时的情况。但是冒泡排序也是初学者必须要掌握的一种基础算法。
原理:
它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
以下图片来源于百度百科
代码样例示范:
#include<stdio.h>
int main(){
int i,j;
int n;
int arr[100]={0};
printf("请输入数组个数: ");
scanf("%d",&n);
printf("请输入数组:");
for(i=0;i<n;i++)
scanf("%d",&arr[i]);
for ( i = 0; i < n - 1; i++) { //循环n-1次,
for ( j = 0; j < n - 1 - i; j++) { //逐渐减少是因为最后面最先确认好
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
printf("冒泡排序之后:");
for(i=0;i<n;i++)
printf("%d ",arr[i]);
return 0;
}
上述代码可以做一个优化,就是通过判断一轮比较是否存在交换,若不存在交换,则说明已经按照要求成功排序,可以考虑多加一个参数进行判断,然后直接退出;这样一来则会节省时间。
时间复杂度:
若数组初始状态是正序的话,一趟扫描就可以完成,所以比较次数C和记录移动次数M达到最少,
则C=n-1,M=0。
如果是若初始文件是反序的,需要进行 n -1 趟排序。每趟排序要进行 n-i 次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到 最大值
冒泡排序的最坏时间复杂度为。
算法稳定性
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会再交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
快速排序
快速排序是基于冒泡排序的一种改进。
原理:
快速排序采用的是分治思想,即在一个无序的序列中选取一个任意的基准元素x,利用x将待排序的序列分成两部分,前面部分元素均小于或等于基准元素,后面部分均大于或等于基准元素,然后采用递归的方法分别对前后两部分重复上述操作,直到将无序序列排列成有序序列。
代码样例示范
void quick_sort(int arr[], int left, int right) {
if (left >= right) {
return;
}
int i = left, j = right, key = arr[left];
while (i < j) {
while (i < j && arr[j] >= key) {
j--;
}
if (i < j) {
arr[i++] = arr[j];
}
while (i < j && arr[i] <= key) {
i++;
}
if (i < j) {
arr[j--] = arr[i];
}
}
arr[i] = key;
quick_sort(arr, left, i - 1);
quick_sort(arr, i + 1, right);
}
时间复杂度:
最好情况下,每次划分都能将待排序序列划分为两个长度相等的子序列,此时时间复杂度为O(nlogn)。最坏情况下,每次划分都不能将待排序序列划分为两个长度相等的子序列,此时时间复杂度为O(n^2)。平均情况下,时间复杂度为O(nlogn)。
算法稳定性:
快速排序是不稳定的排序算法。因为当待排序序列中存在多个相同的元素时,快速排序可能会改变它们的相对位置。
选择排序
选择排序(Selection Sort)是一种简单直观的排序算法。
原理
每次从未排序的部分选择出最小(或最大)的元素,将其放到已排序序列的末尾,直到所有元素都被排序。
- 从未排序的序列中找到最小(或最大)的元素。
- 将找到的最小(或最大)元素与未排序序列的第一个元素交换位置。
- 在剩余的未排序序列中重复步骤1和2,直到所有元素都被排序。
(图片来源于百度)
代码样例示范
#include <stdio.h>
void selectionSort(int arr[], int n) {
int i, j, min_idx;
for (i = 0; i < n-1; i++) {
min_idx = i; //记录此时的下标
for (j = i+1; j < n; j++) {
if (arr[j] < arr[min_idx]) //找到最小的数值的下标
min_idx = j;
}
int temp = arr[min_idx]; //进行置换
arr[min_idx] = arr[i];
arr[i] = temp;
}
}
int main() {
int arr[50]={0};
int n,i;
printf("数组元素个数: ");
scanf("%d",&n);
printf("Original array: ");
for (i = 0; i < n; i++)
scanf("%d", &arr[i]);
selectionSort(arr, n);
printf("Sorted array: ");
for (i = 0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
时间复杂度
O(n^2),
其中n是待排序数组的长度。这是因为选择排序的每一轮都需要找到未排序序列中的最小(或最大)元素,需要进行n-1次比较。总共有n-1轮,所以平均情况和最坏情况下的时间复杂度都是O(n^2)。
算法稳定性
选择排序是一种不稳定的排序算法,即相等元素的相对顺序可能会改变。
例如: 对于序列[3, 3, 1],在第一轮选择后,第一个3会与1交换位置,导致序列变为[1, 3, 3]。因此,选择排序在某些情况下可能无法保持相等元素的相对顺序。
插入排序
一种简单直观的排序算法。
定义
直接插入排序是一种将待排序数据按照插入的方式,逐个插入到已排好序的有序数列中的算法。
原理
直接插入排序的核心思想是将待排数据分为两部分,一部分为已排序好的有序数组,一部分为待排序的无序数组,每次从待排序数组中取出一个元素,将它插入到有序数组中的合适位置。具体实现时,我们可以从第二个元素开始,将当前元素插入到已排序序列中,直到所有的元素插入完毕。
代码样例
#include <stdio.h>
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;
}
}
int main() {
int arr[50]={0};
int n,i;
printf("数组元素个数: ");
scanf("%d",&n);
printf("Original array: ");
for (i = 0; i < n; i++)
scanf("%d", &arr[i]);
insertionSort(arr, n);
printf("Sorted array: ");
for (i = 0; i < n; i++)
printf("%d ", arr[i]);
return 0;
}
时间复杂度
在最好情况下(即待排序数组本身就是有序的情况下),直接插入排序的时间复杂度为O(n),其中n为待排序数组的长度;在最坏情况下(即待排序数组本身就是逆序的情况下),时间复杂度为O(n^2);平均情况下,时间复杂度为O(n^2)。
算法稳定性
直接插入排序是一种稳定的排序算法,即对于具有相同关键字的元素,在排序前后它们的相对位置不会改变。
二分查询
二分查找(Binary Search)是一种常用的快速查找算法,也叫折半查找。
原理
将有序数组分成左右两个区间,每次都取中间位置的元素进行比较,如果中间位置元素等于目标值,则查找成功;如果中间位置元素大于目标值,则在左区间继续查找;否则在右区间继续查找,直到找到目标位置或区间为空为止。
代码实现
#include <stdio.h>
#include<string.h>
int binarySearch(int arr[], int l, int r, int x) {
while (l <= r) {
int mid = l + (r - l) / 2;
if (arr[mid] == x) {
return mid;
}
if (arr[mid] < x) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return -1;
}
int main() {
int arr[10]={0} ;
int n,i;
int x ;
printf("请输入数组个数:");
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&arr[i]);
printf("请输入要查找的数字: ");
scanf("%d",&x);
int result = binarySearch(arr, 0, n - 1, x);
if (result == -1) {
printf("Element not found\n");
} else {
printf("Element found at index %d\n", result);
}
return 0;
}
样例截图:
算法的时间复杂度: O(log n)
希望以上对大家有所帮助,由于时间准备的比较少,后续也会在此片章之中不断完善各种排序。
如果上述文章存在一些问题也可以私信纠正。