时间复杂度: 最好 : O ( n ) 最坏 : O ( n 2 ) 平均时间复杂度 : O ( n 2 ) 最好:O(n)~~~~最坏:O(n^2)~~~~平均时间复杂度:O(n^2) 最好:O(n) 最坏:O(n2) 平均时间复杂度:O(n2)
稳定性:稳定
优化:采用二分法
c复制代码
int a[10]={2,42,42,1,64,35,6,32,4354,78};
void InsertSort(int *suzu){ //插入排序
for (int i=1;i<10;i++){
int a=suzu[i],j=i;
if (suzu[i]<suzu[i-1]){
for (;j>=0 && j-1>=0;j--){
if (a>=suzu[j-1])
break;
if (a<suzu[j-1])
suzu[j]=suzu[j-1];
}
suzu[j]=a;
}
}
}
最坏情况: O ( n 2 ) ( 直接退化成插入排序 ) 当 n 在某个范围内 : O ( n 1.3 ) O(n^2)~~_{(直接退化成插入排序)}~~~当n在某个范围内:O(n^{1.3}) O(n2) (直接退化成插入排序) 当n在某个范围内:O(n1.3)
最优情况: O ( N log 2 N ) O(N\log_2N) O(Nlog2N)
稳定性:不稳定
适用性:适用于顺序表,不适用于链表
c复制代码
void ShellSort(int *suzu){ //希尔排序
for (int k=10/2;k>=1;k/=2) {
for (int i=k;i<10;i++){
int a=suzu[i],j=i;
if (suzu[i]<suzu[i-k]){
for (;j>=0 && j-k>=0;j-=k){
if (a>=suzu[j-k])
break;
if (a<suzu[j-k])
suzu[j]=suzu[j-k];
}
suzu[j]=a;
}
}
}
}
冒泡排序
空间复杂度: O ( 1 ) O(1) O(1)
时间复杂度: 最好 : O ( n ) 最坏 : O ( n 2 ) 平均 : O ( n 2 ) 最好:O(n)~~~最坏:O(n^2)~~~~平均:O(n^2) 最好:O(n) 最坏:O(n2) 平均:O(n2)
稳定性:稳定
适用:顺序表、链表
c复制代码
void BubbleSort( int *suzu){ //冒泡排序
for (int i=0;i<10-1;i++){
int sign=false;
for (int j=0;j<10-1-i;j++){
if (suzu[j]>suzu[j+1]){
int a=suzu[j];
suzu[j]=suzu[j+1];
suzu[j+1]=a;
sign=true;
}
}
if (sign==false)
return;
}
}
//鸡尾酒排序算法
void Swap(int *a,int *b){
int c=*a;
*a=*b;
*b=c;
}
void Logic(int *array){
int len=8;
int front=0,rear=len-1;
_Bool tag=false; //false代表未完成排序
while (front<rear && tag==false) {
tag=true;
for (int i = front; i < rear; i++) {
if (array[i] > array[i + 1]) {
Swap(&array[i], &array[i + 1]);
tag = false;
}
}
rear--;
for (int i = rear; i > front; i--) {
if (array[i] < array[i - 1]) {
Swap(&array[i], &array[i - 1]);
tag = false;
}
}
front++;
}
}
空间复杂度: O ( 递归深度 ) O(递归深度) O(递归深度) 最好: O ( log 2 h ) O(\log_2h) O(log2h) 最坏: O ( h ) ( 树最高 ) O(h)~~~_{(树最高)} O(h) (树最高)
时间复杂度: O ( n ∗ 递归深度 ) = > 最好、平均 : O ( n log 2 n ) 最坏 : O ( n 2 ) O(n*递归深度)=>~~最好、平均:O(n\log_2n)~~最坏:O(n^2) O(n∗递归深度)=> 最好、平均:O(nlog2n) 最坏:O(n2)
有序序列使用快速排序性能最差,因为树最高,递归深度最大。
稳定性:不稳定
c复制代码
int QSort(int *array,int head,int tail){ //快速排序
int mid=array[head];
while (head<tail){
while (array[tail]>=mid && head<tail){
tail--;
}
array[head]=array[tail];
while (array[head]<=mid && head<tail){
head++;
}
array[tail]=array[head];
}
array[head]=mid;
return head;
}
void QS2(int *array,int head,int tail){ //快速排序递归排序每一个分表
if (head<tail){
int a=QSort(array,head,tail);
QS2(array,head,a-1);
QS2(array,a+1,tail);
}
}
void QuickSort( int *array){
int head=0,tail=9;
QS2(array,head,tail);
}
直接选择排序
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
稳定性:不稳定
适用:顺序表、链表
c复制代码
void SimpleSelect( int *array){ //直接快速排序
for (int i=0;i<10-1;i++){
for (int j=i+1;j<10;j++){
if (array[i]>array[j]){
int a=array[i];
array[i]=array[j];
array[j]=a;
}
}
}
}
简单选择排序
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
稳定性:不稳定
适用:顺序表、链表
c复制代码
void swap(int *a,int *b){
int temp = *a;
*a = *b;
*b = temp;
}
void selection_sort(int arr[], int len){
int i,j;
for (i = 0 ; i < len - 1 ; i++){
int min = i;
for (j = i + 1; j < len; j++){
if (arr[j] < arr[min])
min = j;
swap(&arr[min], &arr[i]);
}
}
}
建堆过程:关键字对比次数不超过 4 n 4n 4n,建堆时间复杂度: O ( n ) O(n) O(n)
时间复杂度: O ( n log 2 n ) O(n\log_2n) O(nlog2n)
空间复杂度: O ( 1 ) O(1) O(1)
稳定性:不稳定
堆插入元素:将新插入元素放到堆尾,然后调整成大(小)顶堆。
堆删除元素:用堆低元素替代被删除元素,然后调整成大(小)顶堆。
每上升一次对比一次关键字,每下降一次可能对比一次、可能对比两次关键字。
c复制代码
void BigHeapSort( int *array){ //堆排序
for (int k=(10-1);k>=0;k--){
for (int i = k / 2; i >= 0; i--) {
int max = array[i];
for (int j= i*2;j<= k;j*=2) {
if (array[j] < array[j + 1] && j < k) {
j++;
}
if (array[i] < array[j]) {
array[i] = array[j];
i = j;
} else
break;
}
array[i] = max;
}
int a=array[0];
array[0]=array[k];
array[k]=a;
}
}
归并排序
将多个有序数组进行合并。
归并树:归并排序形态上是倒立的 k 叉树。二叉树第 h 层最多有 k h − 1 k^{h-1} kh−1个节点,若树高为 h ,则 n ≤ k h − 1 n\le k^{h-1} n≤kh−1,归并总次数是 ⌊ log k n ⌋ + 1 \lfloor\log_kn\rfloor+1 ⌊logkn⌋+1 (k为归并路数,n为元素个数)。
每次归并时间复杂度: O ( n ) O(n) O(n)
时间复杂度: O ( n log k n ) ( 每趟归并时间为 n ) O(n\log_kn)~~~_{(每趟归并时间为n)} O(nlogkn) (每趟归并时间为n)
空间复杂度: O ( n ) O(n) O(n)
稳定性:稳定
c复制代码
void TwoMergeSort(int *array1,int *array2){ //二路归并排序
BubbleSort(array1);
BubbleSort(array2);
int len1=5,len2=5;
int target[10];
int tar_len=0,point2=0;
for (int i=0;i<len1;i++){ //array1长度为5
for (int j=point2;j<len2;j++){ //array2长度为5
if (array1[i]<=array2[j]){
target[tar_len++]=array1[i];
break;
}
if (array1[i]>array2[j]){
target[tar_len++]=array2[j];
point2++;
}
}
if (point2==len2)
target[tar_len++]=array1[i];
}
while (point2<len2)
target[tar_len++]=array2[point2++];
}
(桶)基数排序
桶类型排序区别:
基数排序:根据键值的每位数字来分配桶;
计数排序:每个桶只存储单一键值;
桶排序:每个桶存储一定范围的数值。
步骤:
初始化队列个数(r):有多少种类型的数字就初始化多少个队列,一般初始化10个;
每一轮依次按照"个十百..."位的大小将元素加入相应队列的队尾;(一趟耗时 n)
加入完成后依次从每个队头取出所有元素组成新的序列;(一趟耗时 r)
重复 b。
分配次数(排序次数):依据整个序列中最大位的元素。
空间复杂度: O ( r ) O(r) O(r)
时间复杂度: O ( d ∗ ( n + r ) ) ( d 为排序次数, n 为元素个数, r 为队列个数 ) O(d*(n+r))~~~~~~_{(d为排序次数,n为元素个数,r为队列个数)} O(d∗(n+r)) (d为排序次数,n为元素个数,r为队列个数)