十大排序算法学习

article/2025/10/13 2:19:36

Sort

排序类算法是非常常见的算法,包括了比较类排序与非比较类排序

排序能够解决很多问题,有的编程语言也提供了一些排序算法函数(比如C++的sort)但是掌握基本的排序算法原理以及写法仍然是很重要的,并且排序也是面试常考的题目。

菜鸟教程给出了排序算法的复杂度描述

解释

  1. n指的是数据规模,即正常的大O表达法的n
  2. k指的是“桶”的个数
  3. in-place指占用常数级别的内存,不需要额外占用内存,Out-place则相反
  4. 稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同

目录

比较类排序

冒泡排序

快速排序

简单选择排序

堆排序

简单插入排序

希尔排序

归并排序

非比较类排序

计数排序

桶排序

基数排序


交换排序

Bubble Sort

Bubble Sort,冒泡排序,冒泡排序的基本思想是重复的访问数据,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,

How it works

  1. 比较相邻元素,如果前面的比后面的大,就交换
  2. 对所有相邻元素重复操作
  3. 对所有元素重复如上操作
  4. 重复如上步骤

Code

示意图

代码

#include<iostream>
#include<iomanip>
using namespace std;
void BubbleSort(int* a, int len) {for (int i = 0; i < len - 1; i++) {                    //Bubble Sort的实现主体for (int j = 0; j < len - 1; j++) {if (a[j] > a[j + 1]) {int temp = a[j];a[j] = a[j + 1];a[j + 1] = temp;}}}
}

冒泡排序改进版:

考虑这样一个序列{2,1,3,4,5,6,7,8},除了最开始的2,1,其余的元素都已经有序,但是在执行冒泡排序的时候仍然会执行整个比较流程,但实际上他又是多余的。

这里我们可以这样修改

void BubbleSort(int* a, int len) {                         //改进版bool swap = true;                                      //增加控制变量for (int i = 0; i < len - 1 && swap; i++) {            //如果控制变量为false,表明数任取两个元素都已经有序,那么整体自然也有序swap = false;for (int j = 0; j < len - 1; j++) {if (a[j] > a[j + 1]) {int temp = a[j];a[j] = a[j + 1];a[j + 1] = temp;swap = true;}}}
}

复杂度分析

如果是优化过后冒泡排序,而整个数据都是有序的,那么冒泡排序就不需要交换数据,此时只执行n-1次比较,时间复杂度为O(n),但是如果是最坏的情况,每次都要交换,那么就需要1+2+3+…+n-1 = n(n-1)/2,时间复杂度为O(n2),所以总的时间复杂度为O(n2)

返回目录


Quick Sort

Quick Sort,快速排序,是一种分治算法,每次将一组数据分成两个区域,比基准值大的排一个区域,比基准值小的排另一个区域,最终使得整个数据有序,也是冒泡排序的升级版

How it works

  1. 首先选定一个元素,作为所有元素的基准(pivot)
  2. 排序元素,比基准小的排一边,比基准大的元素排另一边
  3. 在两个边区重复如上操作

Code

void QuickSort(int* a, int left,int right) {//算法导论写法if (left > right) {return;}int pivot = a[right];                   //定义基准pivotint fast = left;						//定义快慢指针int slow = left;for (; fast < right;fast++) {           //QuickSort实现主体if (a[fast] <= pivot) {int temp = a[fast];a[fast] = a[slow];a[slow] = temp;slow++;}}a[right] = a[slow];a[slow] = pivot;QuickSort(a, 0, slow - 1);               //二分区间递归QuickSort(a, slow + 1, right);
}
void QuickSort(int* a, int start,int end) {//选第一个元素为基准if (start > end) {return;}int key = a[start];int left = end, right = end;for (; left > start; left--) {if (a[left] >= key) {swap(a[right],a[left]);right--;}}a[start] = a[right];a[right] = key;cout << key << ' ' << right + 1 << endl;QuickSort(a, start, right - 1);QuickSort(a, right + 1, end);
}

快排的递归还有一种写法:

int Mid(int* a, int begin, int end) {int key = a[end];int left = begin;int right = end;while (left < right) {while (left < right && a[left] <= key) {left++;}if (left < right) {a[right--] = a[left];}while (left < right && a[right] >= key) {right--;}if (left < right) {a[left++] = a[right];}}a[left] = key;return left;
}
void QuickSort(int* a, int begin, int end) {if (begin > end) {return;}int mid = Mid(a, begin, end);QuickSort(a, begin, mid - 1);QuickSort(a, mid + 1, end);
}

以上都是使用了递归写法,但是递归众所周知耗时很久,那么有没有非递归写法呢?

答案是有的:

int Mid(int* a, int begin, int end) {int key = a[end];int left = begin;int right = end;while (left < right) {while (left < right && a[left] <= key) {left++;}if (left < right) {a[right--] = a[left];}while (left < right && a[right] >= key) {right--;}if (left < right) {a[left++] = a[right];}}a[left] = key;return left;
}
void QuickSort(int* a, int left, int right) {//非递归写法stack<int> s;s.push(left);s.push(right);while (!s.empty()) {int tempRight = s.top();s.pop();int tempLeft = s.top();s.pop();int mid = Mid(a, tempLeft, tempRight);if (tempLeft < mid - 1) {s.push(tempLeft);s.push(mid - 1);}if (tempRight > mid + 1) {s.push(mid + 1);s.push(tempRight);}}
}

复杂度分析

快速排序算法的时间复杂度主要取决于基准的选择,如果基准选的好,每次都能是处于区间数列中间的数,那么快速排序就会运行得非常快,根据递归调用可知,只需要log2n次调用,每次需要比较n / i(i为划分次数)个数字,总体复杂度为O(nlogn),但是如果基准选的不好,每次都是区间数列的边缘数,那么就意味着大量的递归调用和大量的比较,此时复杂度为O(n^2)

空间性能上,考虑递归调用次数,最好的情况就是O(logn),最坏情况为O(n)。

快速排序优化

1.优化基准的选取

考虑到快速排序基准选择对快速排序算法运行时间影响的重要性,我们可以通过优化基准的选择来改进快速排序算法。

1.随机选取

在left与right之前随机选取一个数作为基准

2.三数取中

int mid = left + (right - left) / 2;
if  (a[left] < a[right]){swap(a[left],a[right]);
}
if  (a[mid] < a[right]){swap(a[mid],a[right]);
}
if  (a[mid] < a[left]){swap(a[mid],a[left]);
}
int pivot = a[left];

3.九数取中

对于小数组三数取中可能已经足够解决问题,但是如果数组更大,可以采用九数取中。

先从数组中分3次取样,每次取3个数,从三个样品中取出中数,然后从这3个中数当中再取出1个中数作为pivot

2.优化小数组时的排序方案

虽然快速排序算法非常强大,但是如果我们使用快速排序算法去解决一些非常简单的排序问题,有时候未免有些大材小用。因此,我们可以在数据量小的时候直接使用插入排序,因为插入排序是简单排序当中性能相对最优的。

返回目录


选择排序

Selection Sort

Selection Sort,中文名简单选择排序,就是依次筛选出元素中最大(小)的元素,排列在数组的某一侧

How it works

Selection Sort的执行过程,主要是利用双循环,先确定第一个元素一定是所有元素中最小(大)的,然后再排序第二个最小(大)的,逐渐递进,从而实现排序

算法执行

  1. 从第一个数组元素开始,获取一个数组元素,记为a
  2. 获取当前获取到的数组元素后一位的元素,这里记为b
  3. 如果b小于a就交换ab,否则不交换
  4. 重复执行2-3直至数组结尾
  5. 当4执行完毕后,重复执行1-4直至数组结尾

Code

#include<iostream>
#include<iomanip>
using namespace std;
void SelectionSort(int* a, int len) {for (int i = 0; i < len; i++) {                    //Selection Sort的实现主体int index = i;for (int j = i + 1; j < len; j++) {if (a[index] > a[j]) {index = j;}}int temp = a[index];a[index] = a[i];a[i] = temp;}
}

复杂度分析

对于简单选择排序,如果所有的数据都是有序的,那么也只需要n-1次比较,时间复杂度为O(n)如果是最坏的情况,就需要1+2+3+…+n-1 = n(n - 1)/2次比较,时间复杂度为O(n^2)

但是要注意,因为每次只对索引进行操作,而冒泡排序对数值操作,所以实际上简单选择排序的运算时间性能上还是比冒泡排序要好。

返回目录


Heap Sort

Heap Sort,中文名堆排序,是选择排序的升级版

要了解堆排序,首先我们要了解这一数据结构。

堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆 (左图所示) 或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆(右图所示)。

因此我们可以得出堆这一数据结构的一个重要性质:根结点一定是整个树中的最大(最小)值对应的结点。

How it works

假设我们当前的堆排序利用大顶堆,那么首先我们将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走,然后将剩余的序列重新构造成一个堆,这样就会得到到剩下的元素中的最大。如此反复执行,便能得到有序序列了

Code

需要注意,由于完全二叉树的性质,所以数组从1开始会相对容易理解。

void HeapAdjust(int* a,int i,int len) {//大顶堆int s = i, temp = a[i];for (int j = 2 * i; j <= len;j *= 2) {if (j < len && a[j] < a[j + 1]) {j++;}if (temp >= a[j]) {break;}a[s] = a[j];s = j;}a[s] = temp;
}
void HeapSort(int* a, int len) {//升序排序int i;for (i = len / 2; i > 0; i--) {HeapAdjust(a,i,len);}for (i = len; i > 1;i--) {int temp = a[i];a[i] = a[1];a[1] = temp;HeapAdjust(a,1,i - 1);}
}

复杂度分析

注意我们的堆排序起点是从完全二叉树最下层的最右边的非终端结点开始的,他只比较当前的结点和孩子判断是否需要交换,所以时间复杂度为O(n)

构建堆时,根据完全二叉树的性质,最大深度为log2n+1,所以每次构建堆都需要logn的时间复杂度,总共进行n-1次,所以时间复杂度为O(nlogn)

由于堆排序不依赖于数据本身是否有序,所以堆排序在时间性能上相当稳定,在任何情况下都是O(nlogn)

而堆排序也不依赖于额外的空间,所以堆排序的空间复杂度也很低,但是堆排序由于是跳跃性的,所以堆排序也是一种不稳定的排序算法。

返回目录


插入排序

Insertion Sort

Insertation Sort,中文名插入排序,一般说到插入排序,指的都是简单插入排序

How it works

Insertation Sort的工作过程,实际上就是从第i项(a[i - 1],i>=1)开始,不断对前i-1项进行排序,最后再将第i项放入其中。

算法执行

  1. 从第一项数据开始,默认其已经排好序
  2. 取出下一个元素,从该元素开始(不包括该元素)从后往前扫描
  3. 如果扫描到的元素大于该元素,则将当前扫描到的元素后移
  4. 重复步骤3,直到该元素大于当前扫描到的元素
  5. 将该元素插入到新位置
  6. 重复如上步骤2-5

Code

#include<iostream>
#include<iomanip>
using namespace std;
void InsertationSort(int* a, int len) {for (int i = 1; i < len; i++) {                 //Insertation Sort的实现主体int key = a[i];int j = i - 1;while (j >= 0 && a[j] > key) {a[j + 1] = a[j];j--;}a[j + 1] = key;}
}

复杂度分析

首先考虑最好的情况,如果数据本身已经有序,那么只需进行n-1次比较,此时时间复杂度为O(n),下面考虑最坏的情况,即整个数据都是逆序,此时需要比较和移动的次数都大约为n^2 / 4次,总的时间复杂度为O(n^2)

但是相比于冒泡排序和简单选择排序,插入排序的效率还是比他们高

折半插入排序

本质上就是利用二分法找到待插入的元素需要插入的位置

void InsertionSort(int* a, int len) {//升序for (int i = 1; i < len; i++) {int j = i - 1;int key = a[i];int l = 0, r = j,mid;while (l <= r) {mid = (l + r) / 2;if (a[mid] <= key) {l = mid + 1;}else {r = mid - 1;}}for (int x = i; x > l; x--) {a[x] = a[x - 1];}a[l] = key;}
}

返回目录

希尔排序

Shell Sort

Shell Sort,希尔排序,简单插入排序的改进版

How it works

希尔排序的思想是,首先我们将n个数据分组,然后对每一个组进行简单插入排序,完成后再细分组,直到组数为1为止,此时进行最后一次插入排序,循环结束,排序完成。

此处引用简书上希尔排序的一个图片,非常清楚的演示了希尔排序思想及其执行过程

关于希尔排序如何分组,至今仍是一个数学难题,一般我们写题目使用二分(d = d / 2)即可

并且由于记录的跳跃性,所以希尔排序算法是一种不稳定的排序算法。

void ShellSort(int* nums,int len){int temp,i,j,d;for (d = len / 2;d >= 1;d /= 2){for (i = d;i < len;i++){temp = nums[i];for (j = i - d;j >= 0 && temp < nums[j];j -= d){nums[j+d] = nums[j];}nums[j+d] = temp;}}
}

复杂度分析

希尔排序的复杂度取决于分组和数据的组有序程度,其中如何分组是最为重要的,根据分组的不同,时间复杂度为介于O(n1.3)-O(n2)之间

但是总的来说,由于希尔排序的跳跃性,所以希尔排序的时间性能还是比简单插入排序来的好。

归并排序

Merge Sort

Merge Sort,归并排序,是一种基于归并操作修改而来的算法。该算法采用分治的办法,先使子序列有序,再使子序列段间有序,最后归并

How it works

  1. 将序列分成两个子序列
  2. 对子序列采用归并排序
  3. 将排序好的两个子序列归并

Code

递归版本示意图

递归代码

void Merge(int* tempArr, int* ans, int start, int mid, int end) {int i, j, k = start;for (j = mid + 1, i = start; i <= mid && j <= end; k++) {if (tempArr[j] > tempArr[i]) {ans[k] = tempArr[i++];}else {ans[k] = tempArr[j++];}}for (; i <= mid; k++) {ans[k] = tempArr[i++];}for (; j <= end; k++) {ans[k] = tempArr[j++];}
}
void MergeSort(int* a, int* ans, int start, int end) {//递归int* tempArr = new int[end + 1];if (start == end) {ans[start] = a[end];}else {int mid = (start + end) / 2;MergeSort(a, tempArr, start, mid);MergeSort(a, tempArr, mid + 1, end);Merge(tempArr, ans, start, mid, end);}
}

非递归版本

void Merge(int* tempArr, int* ans, int start, int mid, int end) {int i, j, k = start;for (j = mid + 1, i = start; i <= mid && j <= end; k++) {if (tempArr[j] > tempArr[i]) {ans[k] = tempArr[i++];}else {ans[k] = tempArr[j++];}}for (; i <= mid; k++) {ans[k] = tempArr[i++];}for (; j <= end; k++) {ans[k] = tempArr[j++];}
}
void MergePass(int* a,int* ans,int k,int size) {int i = 1;int j;while (i <= size - 2 * k + 1) {Merge(a,ans,i,i + k - 1,i + 2 * k - 1);i += 2 * k;}if (i < size - k + 1) {//归并最后两个序列Merge(a, ans, i, i + k - 1, size);}else {//序列只有一个数for (j = i; j <= size; j++) {ans[j] = a[j];}}
}
void MergeSort(int* a, int size) {int* ans = new int[size];int k = 1;while (k  < size) {MergePass(a,ans,k,size);k = 2 * k;MergePass(ans,a,k,size);k = 2 * k;}
}

复杂度分析

由于归并排序每一趟的归并过程都需要将数组中一确定长度的有序序进行两两归并,因此我们就需要遍历整个数组,这需要O(n),而归并过程需要执行log2n次,所以总的时间复杂度为O(nlogn),同时由于每次运行都需要额外的空间来保存当前的归并结果,所以空间复杂度为O(n)

同时,因为归并排序会逐个比较,所以归并排序是一种稳定的算法。

但是,由于使用递归会造成log2n的栈深度,使用归并排序的时候还是使用非递归(迭代)方式更好。

非比较类排序

Counting Sort

Counting Sort,计数排序,该算法要已知当前数据的最大项与最小项

How it works

1.首先求得当前数据之中的最大值与最小值

2.定义一个计数数组,全部赋初值为0

3.一次遍历所有数据,记录各个数据出现的次数

4.再遍历一次计数数组,根据数组中ai项的个数重新给数据赋值,遍历结束,排序完成

Code

void CountingSort(int* a, int len) {//不考虑负数int max = INT_MIN, i;for (i = 0; i < len; i++) {max = a[i] > max ? a[i] : max;}int* count = new int[max + 1];for (i = 0; i <= max; i++) {count[i] = 0;}for (i = 0; i < len; i++) {count[a[i]]++;}i = 0;for (int x = 0; x <= max; x++) {while (count[x] != 0) {a[i++] = x;count[x]--;}}
}

复杂度分析

计数排序是一种稳定的排序算法,其时间复杂度和空间复杂度均为O(n+k),当数据比较小的时候,选择计数排序是相当合适的。

BucketSort

桶排序首先假设所有的数据都服从均匀分布,在此基础上将数组的所有的元素均匀的分布到数量有限的每个桶里,再对每个桶进行单独的排序(此事发生的排序可能是别的排序算法或者继续递归桶排序),最后将所有桶的元素取出即形成一个有序的序列。

桶排序的思想,是一种极端的分治思想,其基于数组的所有元素都服从均匀分布,因此可以给数组的元素划定范围,根据范围确定有多少个桶。

此时就可以基于某种映射函数f,将待排序的数组元素映射到桶中,数学表示为f:k->B[i],其中k为待排序的数组元素,B[i]为第i个桶。对每个桶进行排序,合并每个桶的序列,就完成了桶排序。

一般来说,映射函数为f = a[i] / k,k ^ 2 = n,n为数组元素个数

由桶排序的基本概念及定义可知,为了提升桶排序的效率,我们需要:

1.在空间充足的情况下尽可能提升桶的数量

2.使用的映射函数f能保证数据均匀的分布在各个桶中

3.对于桶中的元素,选择的排序算法时候合适

How it works

1.设定一个数组表示桶

2.遍历数组,将数组元素放入桶

3.对非空桶进行排序

4.将桶中的元素放回原数组中

Code

#define NBUCKET 6  // 桶的数量
#define INTERVAL 10  // 每个桶能存放的元素个数
typedef struct Bucket {int data;Bucket* next;
};
Bucket* InsertionSort(Bucket* list) {Bucket* k, * nodeList;if (list == NULL || list->next == NULL) {return list;}nodeList = list;k = list->next;nodeList->next = NULL;while (k != NULL) {Bucket* ptr;if (nodeList->data > k->data) {Bucket* tmp;tmp = k;k = k->next;tmp->next = nodeList;nodeList = tmp;continue;}for (ptr = nodeList; ptr->next != 0; ptr = ptr->next) {if (ptr->next->data > k->data)break;}if (ptr->next != 0) {Bucket* tmp;tmp = k;k = k->next;tmp->next = ptr->next;ptr->next = tmp;continue;}else {ptr->next = k;k = k->next;ptr->next->next = 0;continue;}}return nodeList;
}
void BucketSort(int* arr,int len) {int i, j;Bucket** buckets;buckets = new Bucket * [NBUCKET];for (i = 0; i < NBUCKET; ++i) {buckets[i] = NULL;}for (i = 0; i < len; ++i) {Bucket* current;int pos = arr[i] * 10;current = new Bucket{ arr[i],buckets[pos] };buckets[pos] = current;}for (i = 0; i < NBUCKET; ++i) {buckets[i] = InsertionSort(buckets[i]);}for (j = 0, i = 0; i < NBUCKET; ++i) {Bucket* node = buckets[i];while (node) {arr[j++] = node->data;node = node->next;}}
}

复杂度分析

对于桶排序,最好的情况自然是数组已经有序,此时我们只需要完成放桶,放回的操作,时间复杂度为O(n),空间复杂度为O(n + M),M为桶个数,对于最坏情况,无非所有的桶都要执行排序,那么时间复杂度就退化为O(n^2),由于是依次遍历的,所以桶排序保证了排序算法的稳定性。因此,桶排序是一种平均时间复杂度为O(n + M),空间复杂度为O(n + M)的稳定的排序算法。

基数排序

Radix Sort

基数排序是一种非比较类的排序,它是利用了比较关系的时候存在的优先级的思想。

LSD(最低优先法)

比如,我们对7和15排序,虽然7的个位大于15的个位,但是我们仍然认为15大于7,这是因为比个位权值更高的十位上15的值为1而7为0。这种权值比较的思想贯穿了整个基数排序。

举个简单的栗子:比如我们要对{1,2,47,40,85,74,16,77,27,62}排序,我们首先获得他们当中的最大数85,得知了85包括了十位和个位,又因为十位的权值高于个位,所以我们相当于得到了一个贯穿整个基数排序的权值排列:十位 > 个位

然后,我们只需要从最低优先级的权值开始,将数的对应权值的数放入对应的桶,比如16在个位是6,就放入bucket[6],以此类推,直到整个数组遍历完成,此时按照每个桶中的数,重新放回数组,还是我们前面的例子,此时的结构如下:

接下来我们先按照桶编号,再按照放入桶中的顺序,一次给数组赋值,从而到如下数组:

此时最低优先级的权值已经完成,接下来运行十位这一权值,注意此时我们遍历的数组a是已经更新了的数组a

此时我们再把桶中的数取出,排序完成。

How it works

1.首先计算出最大的数的位数

2.从最低权值开始,遍历数组,放入对应的桶

3.重复2操作直到有序

typedef struct Bucket {int num;Bucket* next;
};
int getMax(int* a, int len) {int max = -65535;for (int i = 0; i < len; i++) {max = max > a[i] ? max : a[i];}return max;
}
void RadixSort(int* a, int len) {int maxNum = getMax(a, len);int maxDigit = 0;while (maxNum) {maxDigit++;maxNum /= 10;}int mod, di = 1;for (int i = 0; i < maxDigit; i++) {Bucket* L = new Bucket[10];for (int i = 0; i < 10; i++) {L[i].next = NULL;}for (int x = 0; x < len; x++) {mod = a[x] / di % 10;if (L[mod].next == NULL) {L[mod].next = new Bucket{ a[x],NULL };}else {Bucket* temp = L[mod].next;while (temp->next) {temp = temp->next;}temp->next = new Bucket{ a[x],NULL };}}di *= 10;int index = 0;for (int i = 0; i < 10; i++) {Bucket* temp = L[i].next;while (temp) {a[index++] = temp->num;temp = temp->next;}}delete[] L;}
}

复杂度分析

由于基数排序先遍历到的数最后一定会出现在前面,所以基数排序是稳定的排序,假设基数排序至少需要k个关键字,数组的长度为n,那么每次排序都需要执行k*(2n + k)次,由于k一般远远小于n,所以可以视为时间复杂度为O(2kn)或者说是线性的时间复杂度。

至于空间复杂度,由于每次都需要开桶,所以需要O(n+k)空间复杂度

参考:(3条消息) 十大排序——最全最详细,一文让你彻底搞懂_Three3333333的博客-CSDN博客

十大经典排序算法(动图演示) - 一像素 - 博客园 (cnblogs.com)


http://chatgpt.dhexx.cn/article/uR32pdKF.shtml

相关文章

十大排序算法(Java)

目录 1.冒泡排序 2.快速排序 3.插入排序 4.希尔排序 5.选择排序 6.堆排序 7.归并排序 8.计数排序&#xff1a;速度快&#xff0c;一般用于整数排序 9.桶排序 10.基数排序 1.冒泡排序 冒泡排序思路&#xff1a;&#xff08;两层for循环&#xff09; 比较相邻的元素。…

十大排序算法(C++)

十大排序算法Sorting algorithm(C) 百度百科&#xff1a; 所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。排序算法&#xff0c;就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地…

十大排序算法——C语言实现

1.冒泡排序 ​ 冒泡排序&#xff08;Bubble Sort&#xff09;也是一种简单直观的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数…

Python实现十大排序算法

1.排序算法概述 非线性时间比较类排序&#xff1a;通过比较来决定元素间的相对次序&#xff0c;由于其时间复杂度不能突破O(nlogn)&#xff0c;因此称为非线性时间比较类排序。 线性时间非比较类排序&#xff1a;不通过比较来决定元素间的相对次序&#xff0c;它可以突破基于比…

Java实现十大排序算法

Java实现十大排序算法 十大排序算法分别为&#xff1a;选择排序、冒泡排序、插入排序、快速排序、归并排序、堆排序、希尔排序、桶排序、计数排序、基数排序。 本篇只是为了方便我在代码中直接复制调用&#xff0c;因此原理和思想解释的并不清楚&#xff0c;想看原理的朋友可…

十大排序算法(C++版)

十大排序算法 前言一、插入排序二、希尔排序三、冒泡排序四、快速排序五、选择排序六、归并排序七、堆排序八、计数排序九、桶排序十、基数排序总结 前言 什么是排序&#xff1f; 排序&#xff1a;将一组杂乱无章的数据按一定规律顺次排列起来。即&#xff0c;将无序序列排成一…

十大排序算法详解

十大排序算法详解 参考程序员必知必会的十大排序算法详解 引言 对于排序的分类&#xff0c;可以将排序算法分为两大类&#xff1a;基于比较和非比较的算法。 基于比较的排序算法可以细分为&#xff1a; 基于交换类&#xff1a;冒泡排序、快速排序基于插入类&#xff1a;直接插入…

JS 实现十大排序算法

文章目录 前言零、十大排序一、冒泡排序&#xff08;bubbleSort&#xff09;二、选择排序&#xff08;selectionSort&#xff09;三、插入排序&#xff08;insertSort&#xff09;四、希尔排序&#xff08;shellSort&#xff09;五、归并排序&#xff08;mergeSort&#xff09;…

十大经典排序算法Java版(动图演示)

文章目录 0 排序算法说明0.1 内部排序和外部排序0.2 比较类排序和非比较类排序0.3 关于时间复杂度0.4 关于稳定性0.5 名词解释&#xff1a; 1 交换排序——冒泡排序&#xff08;Bubble Sort&#xff09;1.1 什么时候最快1.2 什么时候最慢1.3 算法步骤1.4 动图演示1.5 Java实现 …

html之如何让button按钮居中

解决措施&#xff1a;使用center或者div的align属性 示例代码&#xff1a; <html> <body><center><button onClick"clickme()">hit me</button></center><script>function clickme(){alert("123");} </scr…

HTML中让表单和提交按钮居中的方法

表单&#xff1a; form{ width: 500px; /*设置宽度&#xff0c;方便使其居中*/ margin: 40px auto auto auto; /*上右下左*/ font-size: 25px; 提交按钮&#xff1a;div的align属性 <div align"center"><button onClick"clickme()">提交…

android中的Button按钮居中(水平垂直中)

今天发现一个很怪异的事 Android Studio中居然一个简单的按钮水品垂直居中都写不出来 下图为理想效果&#xff1a; 可是当我写原始出代码的时候&#xff08;如下&#xff09;&#xff1a; <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android&quo…

Vue组件居中:文字居中,按钮居中,图片居中等,如何实现在容器中居中

Vue实现组件在容器中居中显示的办法 本文用实验的方法理解各种方法实现居中的效果。 实现水平居中的样式主要有&#xff1a;text-align: center&#xff0c; margin: auto。 当然还有别的方式也可以实现&#xff0c;也会写在下面。 用三个同样的div来控制变量法看效果&#xf…

Contact form 7 提交按钮居中,怎么设置submit button居中显示

Contact form 7 提交按钮居中&#xff0c;怎么设置submit button居中显示 前言 最近公司在做网站&#xff0c;毫无疑问用的是wordpress程序&#xff0c;然后就用到了contact form 7这个插件。单是这个插件的按钮始终无法居中显示&#xff0c;查了很多教程有的让改主题&#x…

tkinter 让按钮居中显示

def ask(self, title, text, btn_comfirm_name"确定", btn_cancel_name"取消", wraplength400):self.master.title(title)tk.Label(self.middle, texttext, bg"#ffffff", wraplengthwraplength,justify"left").pack(pady15)self.botto…

html表单中按钮居中,Ant design StepsForm中如何使底部按钮居中

如图所示,当前有一个StepsForm表单,代码如下(基本就是官网的示例修改的)const Demo: React.FC = () => {const Option = [ {key: 1, value: 111, label: 个人 }, {key: 2, value: 222, label: 合作 }, ] const waitTime = (time: number = 100) => {return new Promise…

layui使按钮居中_button按钮居中的方法

今天在写页面时&#xff0c;发现给button按钮设置居中时&#xff0c;css页面写了text-align"center"&#xff0c;但是不起作用&#xff0c;用了display属性也无作用&#xff0c;试了好多次发现要给button按钮添加个p&#xff0c;然后让p居中就可以了。以下写个test来…

Android IMS 语音通话 vs 视频通话 vs 视频彩铃

背景 以下内容基于Android P code。 主要差异 视频通话比语音通话主要是多了判断是否为视频通话&#xff0c;及视频的显示和传输。如下&#xff1a; video call 视频界面显示控制 界面通过IVideoProvider控制camera的显示并设置TextureView等&#xff0c;Ims service通过IV…

Unity 语音和视频通话快速解决方案——声网 SDK接入指南(Android)

Unity 语音和视频通话快速解决方案——声网 SDK接入指南&#xff08;Android&#xff09; 文章目录 Unity 语音和视频通话快速解决方案——声网 SDK接入指南&#xff08;Android&#xff09;一、前言二、后台创建应用三、获取 SDK四、接入 Agora Voice 语音 SDK1. 导入工程2. 搭…

技术分享| 小程序实现音视频通话

上一期我们把前期准备工作做完了&#xff0c;这一期就带大家实现音视频通话&#xff01; sdk 二次封装 为了更好的区分功能&#xff0c;我分成了六个 js 文件 config.js 音视频与呼叫邀请配置 store.js 实现音视频通话的变量 rtc.js 音视频逻辑封装 live-code.js 微信推拉…