面试系列之排序算法总结(C/C++版本)
Posted 逗逗飞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试系列之排序算法总结(C/C++版本)相关的知识,希望对你有一定的参考价值。
冒泡排序
/*
冒泡排序是一种流行但低效的算法,
它的作用是反复交换相邻的未按次序排列的元素
*/
#include <stdio.h>
void Exchange(int &a,int &b)
// 使用位运算,秀一秀自己的实力
a = a^b;
b = a^b;
a = a^b;
void BubbleSort(int a[],int len)
// 为了保证代码的鲁棒性,我们首先对异常值验证
if(a == NULL || len <= 0)
return;
// 冒泡排序核心代码
for(int i = 0; i < len; i++)
for(int j = len-1; j > i; j--)
if(a[j] < a[j-1])
exchange(a[j],a[j-1]);
时间复杂度O(n²),空间复杂度O(1)
选择排序
/*
简单选择排序
每次经过 n-i 次比较,从序列中选出i之后的最小元素放在第 i 个位置
*/
void SelectSort(int a[],int len)
// 为了保证代码的鲁棒性,我们首先对异常值验证
if(a == NULL || len <= 0)
return;
// 选择排序核心代码
for(int i = 0; i < len; i++)
int min_index = i;
for(int j = i+1; j < len; j++)
// 每轮迭代,目的是找出i后面最小值得下标
if(a[i] > a[j])
min_index = j;
if(min_index != i)
exchange(a[i],a[min_index]);
时间复杂度O(n²),空间复杂度O(1)
插入排序
/*
插入排序
a[0...i]有序,
选择a[i+1]放入到 a[0...i] 合适位置,
使a[0...i+1]有序
*/
void InsertSort(int a[], int len)
for(int i = 1; i < len; i++)
int j = i-1;
int key = a[i];
while(j >=0 && a[j] > key)
a[j+1] = a[j];
j--;
a[j+1] = key;
时间复杂度O(n²),空间复杂度O(1)
快速排序
/*
快速排序通常是实际应用中最好的选择:
因为它平均性能非常好,它的期望时间复杂度是O(nlogn),而且O(nlogn)隐含常数因子非常小
另外它能够进行原址排序
*/
int Partition(int a[], int p, int r)
int i = p;
for(int j = p; j < r; j++)
if(a[j] < a[r])
exchange(a[i],a[j]);
i++;
exchange(a[i],a[r]);
return i;
void QuickSort(int a[],int p,int r)
if(p < r)
int q = Partition(a,p,r);
QuickSort(a,p,q-1);
QuickSort(a,q+1,r);
快速排序最坏的时间复杂度是O(n^2),但平均时间复杂度是O(nlogn)
平均空间复杂度是O(nlogn),最坏空间复杂度是O(n)
归并排序
void merge(int a[], int p, int q, int r)
int n1 = q-p+1;
int n2 = r-q;
int L[n1+1],R[n2+1];
int i,j,k;
for(i = 0; i < n1; i++)
L[i] = a[p+i];
for(i = 0; i < n2; i++)
R[i] = a[q+i+1];//因为下标是从0开始,这里应该+1
L[n1] = 0x7fffffff;
R[n2] = 0x7fffffff;
i = 0, j = 0;
for(k = p; k <= r; k++)
if(L[i] <= R[j])
a[k] = L[i++];
else
a[k] = R[j++];
void mergeSort(int a[],int p,int r)
if(p < r)
int q = (p+r)/2;
mergeSort(a,p,q);
mergeSort(a,q+1,r);
merge(a,p,q,r);
从这个递归树可以看出,第一层时间代价为cn,第二层时间代价为cn/2+cn/2=cn.....每一层代价都是cn,总共有logn+1层。所以总的时间代价为cn*(logn+1).时间复杂度是o(nlogn).
空间复杂度O(n)堆排序
堆是完全二叉树的结构,因此对于一个有n个节点的堆,高度为O(logn)。
最大堆:堆中的最大元素存放在根节点的位置。
除了根节点,其他每个节点的值最多与其父节点的值一样大。也就是任意一个子树中包含的所有节点的值都不大于树根节点的值。
堆中节点的位置编号都是确定的,根节点编号为1,每一层从左到右依次编号。由堆是完全二叉树,可以知道当堆中某个节点的编号为i时,如果这个节点有左右子树,那么左子树的节点编号为2*i,右子树的节点编号为2*i+1(当然这是在根节点编号为1的情况时)。
并且有n个节点的堆中叶子节点的编号为从n/2+1~n。因为假设节点n/2+1不是叶子节点,那么它的左子节点编号(n/2+1)*2=n+1,而节点总共只有n个。完全二叉树的叶子节点只出现在最下面两层。最下层的叶子集中在左边,倒数二层的叶子集中在右边。
维护最大堆函数MAX_HEAPWEIHU(A,i),假定节点i的左右子树已经是最大堆。那么维护堆时,先比较i节点的值与左右节点值的大小,将三个数中的最大值交换到根节点的位置。假设根节点i与左子节点的值交换了,那么左子树就要再次调用MAX_HEAPWEIHU(A,2*i),判断左子树还是不是最大堆,如果是则结束,否则继续调用进行维护。因此调用MAX_HEAPWEIHU(A,i)的时间复杂度为O(logn)
void heapfy(int a[],int index,int heapsize)
int left = index*2;
int right = index*2+1;
int largest = index;
if(left < heapsize && a[index] < a[left])
largest = left;
if(right < heapsize && a[largest] < a[right])
largest = right;
if(largest != index)
swap(a[index],a[largest]);
heapfy(a,largest,heapsize);
void heapSort(int a[],int len)
for(int i = len/2-1; i>=0; i--)
heapfy(a,i,len);
for(int i = len-1; i>=0; i--)
swap(a[i],a[0]);
heapfy(a,0,i);
计数排序
输入数组a[],输出数据存放在b[],临时存储空间c[0...k]
初始化数组c全被设置为0,遍历一遍输入数组a[],如果一个元素的值为i,就将c[i]的值+1;
于是此时的c[i]保存的就是等于i的元素个数,其中i= 0...k
代码中
c[i] = c[i] + c[i-1];
表示多少元素是小于等于i的
void CountingSort(int a[], int *b)
int c[13] = -1;
for(int i = 0; i < 10; i++)
c[a[i]]++;
for(int i = 1; i < 13; i++)
c[i] = c[i] + c[i-1];
printf("hello world\\n");
for(int i = 9; i >=0; i--)
#printf("a[%d] = %d\\t,b[%d] = %d\\t,c[%d] = %d\\n",i,a[i],i,b[i],i,c[a[i]]);
b[c[a[i]]] = a[i];
c[a[i]] = c[a[i]] -1;
时间复杂度是O(k+n),实际应用中档k = O(n)时,一般会采用技术排序,总时间复杂度是O(n)
基数排序
桶排序
以上是关于面试系列之排序算法总结(C/C++版本)的主要内容,如果未能解决你的问题,请参考以下文章