CSDN第一篇文章。。。
1.稳定性比较
插入排序、冒泡排序、二路归并排序及其他线形排序是稳定的
选择排序、希尔排序、快速排序、堆排序是不稳定的
2.时间复杂性比较
插入排序、冒泡排序、选择排序的时间复杂性为O(n2)
其它非线形排序的时间复杂性为O(nlog2n)
线形排序的时间复杂性为O(n);
-------------------------------------------------
选择排序
算法思想:
依次从后面的数组中选出最小的数与前面的交换,
直到倒数第二个数被访问到
选择排序是不稳定的,O(n^2)--n的平方
-------------------------------------------------
/**
* 选择排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void select_sort( int *a, int n )
{
int i, j, min, tmp;
for( i=0; i<n-1; i++ )
{
min = i+1;
for( j=i+2; j<n; j++ )
{
if( a[min] > a[j] ) min = j;
}
if( a[i] > a[min] )
{
tmp = a[i];
a[i] = a[min];
a[min] = tmp;
}
}
return;
}
/*
-------------------------------------------------
冒泡排序
算法思想:
自上而下依次比较相邻的两个数,大的数往下沉
改进:使用一个k值保存每次下沉数的位置,那么
k位置以后的都是排好序的
冒泡排序是稳定的,O(n**2)--n的二次方
-------------------------------------------------
*/
/**
* 冒泡排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void bubble_sort( int *a, int n )
{
int i, j, k, t, tmp;
t = n-1;
for( i=0; i<n; i++ )
{
for( j=0; j<t; j++ )
{
if( a[j] > a[j+1] )
{
tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
k = j+1;
}
}
t = k;
}
return;
}
/*
------------------------------------------------
插入排序
算法思想:
假设前n-1个元素以及排好序,现在将第n个元素放
进去,使前n个元素有些,如此反复,直到所有元素
都插入
插入排序是稳定的,O(n^2)--n的二次方
------------------------------------------------
* 插入排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void insert_sort( int *a, int n )
{
int i, j, t, tmp;
for( i=1; i<n; i++ )
{
t = i;
for( j=i-1; j>=0; j-- ) //从后向前遍历,直到比自己小的数
{
if( a[t] > a[j] )
{
a[j+1] = a[j];
} else
break;
}
a[j+1] = a[t];
}
return;
}
/*
-------------------------------------------------
希尔排序
算法思想:
希尔排序时插入排序的一种,实质上是分组插入排序,
第一次取增量为n/2,以该增量d将元素分为若干组,
每组中的元素下标相差d,对每一组进行直接插入排序,下一次
d = (d+1) / 2,再根据d进行分组,再排序,直到d为1,
所有元素被分为一组排序完成
希尔排序是不稳定的,时间复杂度在O(n*logn)与O(n^2)之间
,比直接插入排序快
-------------------------------------------------
*/
/**
* 希尔排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void shell_sort(int a[], int n)
{
int t;
int i, j;
for(int d=n/2; d>=1; d /= 2) {
for(i=d; i<n; i++) {
//对每组进行插入排序
t = a[i];
for(j=i-d; j>=0; j -= d) {
if(t < a[j]) a[j+d] = a[j];
else
break;
}
a[j+d] = t;
}
}
}
/*
-------------------------------------------------
快速排序
算法思想:
通过一趟扫描后,以一个基准点的左边都比它小,右边都
比它大,又分别对左边和右边进行处理,直到左边和右边
只有一个元素
快速排序是不稳定的,最理想情况算法时间复杂度
O(nlogn),最坏O(n^2),解决办法为每次取中间的数为
基准点
-------------------------------------------------
* 快速排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void quick_sort( int *a, int start, int end )
{
int i = start, j = end, t;
if( start < end )
{
t = a[start];
while( i < j )
{
while( i<j && a[j] > t ) //从后向前扫描
j--;
if( i<j )
{
a[i] = a[j];
i++;
}
while( i<j && a[i] < t ) //从前向后扫描
i++;
if( i<j )
{
a[j] = a[i];
j--;
}
}
a[i] = t; //把基准点放入争取位置
quick_sort( a, 0, i-1 );
quick_sort( a, i+1, end );
}
return;
}
/*
-------------------------------------------------
堆排序
算法思想:
堆排序是一种树形选择排序,堆的根元素为最大值,
完全二叉树能清楚表示堆
首先将元素看作顺序存储的二叉树,使其成为一个堆,
再将根元素与最后一个元素交换,再对前n-1个元素
构建堆,直到只有两个节点的堆
需要两个函数,一个是用于构建的堆的函数,一个是
调用此函数进行排序的函数
堆排序是不稳定的,O(nlogn)
-------------------------------------------------
*/
/**
* 构建堆
*
* @param a -[in,out] -需要构建的数组
*
* @param top -[in] -元素开始位置
*
* @param tail -[in] -元素结束位置
*
* @return -[None]
*/
void sift(int a[], int top, int tail)
{
if(top >= tail) return;
//将堆顶元素,向下筛选放入堆中 ,够成大根堆
int i = top;
int j = i*2+1; //i节点的左子节点
int t = a[i];
while(j <= tail) {
if(j+1 <= tail && a[j] < a[j+1]) j++;
if(t < a[j]) {
a[i] = a[j];
i = j;
j = j*2 + 1;
} else
break;
}
a[i] = t;
}
/**
* 堆排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void heap_sort(int a[], int n)
{
//初始化堆
for(int i=n/2-1; i>=0; i--) {
sift(a, i, n-1);
}
for(int i=0; i<10; i++)
printf("%d ", a[i]);
printf("\n");
//循环n次,每次得到堆中最大值
for(int i=n-1; i>0; i--) {
int t = a[0];
a[0] = a[i];
a[i] = t;
sift(a, 0, i-1);
}
}
/*
-------------------------------------------------
归并排序
算法思想:
归并排序也是分治法,先将相邻元素分为n/2组,对每组
进行排序,再合并成n/4组,依次类推全部合并为一组
结束
归并排序是稳定的,O(nlogn)
-------------------------------------------------
*/
/**
* 合并两个序列
*
* @param a -[in,out] -需要构建的数组
*
* @param start -[in] -元素开始位置
*
* @param mid -[in] -序列分割位置
*
* @param end -[in] -元素结束位置
*
* @return -[None]
*/
void merge( int *a, int start, int mid, int end )
{
int i = start, j = mid;
queue<int> q; //利用队列来作为临时存放空间
while( i < mid && j < end )
{
if( a[i] < a[j] )
{
q.push( a[i] );
i++;
}
else
{
q.push( a[j] );
j++;
}
}
while( i < mid )
{
q.push( a[i] );
i++;
}
while( j < end )
{
q.push( a[j] );
j++;
}
//将在队列中排好序的元素赋值给数组
for( i=start; i<end; i++ )
{
a[i] = q.front();
q.pop();
}
}
/**
* 归并排序
*
* @param a -[in,out] -需要构建的数组
*
* @param start -[in] -元素开始位置
*
* @param mid -[in] -序列分割位置
*
* @param end -[in] -元素结束位置
*
* @return -[None]
*/
void merge_sort( int *a, int start, int end )
{
int mid;
if( start+1 < end )
{
mid = (start+end) / 2 ;
merge_sort( a, start, mid );
merge_sort( a, mid, end );
merge( a, start, mid, end );
}
}
/*
-----------------------------------------------------
基数排序
算法思想:
例如 m 位数的 n个整数,先根据个位数的值放入对应的桶中,
根据桶的顺序提取元素,再根据十位数的值放入对应的桶中,
以此类推
算法复杂度: O(m*n*10)
备注:如372,要得到百位数字:
372 % 1000 / (1000/10) = 3
-----------------------------------------------------
*/
void bucket_sort(int *a, int m, int n) {
queue<int> ques[10];
int mod = 1;
int count = 0;
int index = 0;
for(int i=0; i<m; i++) {
mod = mod*10;
//放入对应桶中
for(int j=0; j<n; j++) {
index = a[j] % mod / (mod/10); //计算位置上的数字
ques[index].push(a[j]);
}
count = 0;
//将桶中数据依次取出
for(int j=0; j<10; j++) {
while(!ques[j].empty()) {
a[count++] = ques[j].front();
ques[j].pop();
}
}
}
}
最近参加校招,复习了各种基本排序,以便笔试,面试派上用场,顺便总结下
1.稳定性比较
插入排序、冒泡排序、二路归并排序及其他线形排序是稳定的
选择排序、希尔排序、快速排序、堆排序是不稳定的
2.时间复杂性比较
插入排序、冒泡排序、选择排序的时间复杂性为O(n2)
其它非线形排序的时间复杂性为O(nlog2n)
线形排序的时间复杂性为O(n);
-------------------------------------------------
选择排序
算法思想:
依次从后面的数组中选出最小的数与前面的交换,
直到倒数第二个数被访问到
选择排序是不稳定的,O(n^2)--n的平方
-------------------------------------------------
/**
* 选择排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void select_sort( int *a, int n )
{
int i, j, min, tmp;
for( i=0; i<n-1; i++ )
{
min = i+1;
for( j=i+2; j<n; j++ )
{
if( a[min] > a[j] ) min = j;
}
if( a[i] > a[min] )
{
tmp = a[i];
a[i] = a[min];
a[min] = tmp;
}
}
return;
}
/*
-------------------------------------------------
冒泡排序
算法思想:
自上而下依次比较相邻的两个数,大的数往下沉
改进:使用一个k值保存每次下沉数的位置,那么
k位置以后的都是排好序的
冒泡排序是稳定的,O(n**2)--n的二次方
-------------------------------------------------
*/
/**
* 冒泡排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void bubble_sort( int *a, int n )
{
int i, j, k, t, tmp;
t = n-1;
for( i=0; i<n; i++ )
{
for( j=0; j<t; j++ )
{
if( a[j] > a[j+1] )
{
tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
k = j+1;
}
}
t = k;
}
return;
}
/*
------------------------------------------------
插入排序
算法思想:
假设前n-1个元素以及排好序,现在将第n个元素放
进去,使前n个元素有些,如此反复,直到所有元素
都插入
插入排序是稳定的,O(n^2)--n的二次方
------------------------------------------------
*/
* 插入排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void insert_sort( int *a, int n )
{
int i, j, t, tmp;
for( i=1; i<n; i++ )
{
t = i;
for( j=i-1; j>=0; j-- ) //从后向前遍历,直到比自己小的数
{
if( a[t] > a[j] )
{
a[j+1] = a[j];
} else
break;
}
a[j+1] = a[t];
}
return;
}
/*
-------------------------------------------------
希尔排序
算法思想:
希尔排序时插入排序的一种,实质上是分组插入排序,
第一次取增量为n/2,以该增量d将元素分为若干组,
每组中的元素下标相差d,对每一组进行直接插入排序,下一次
d = (d+1) / 2,再根据d进行分组,再排序,直到d为1,
所有元素被分为一组排序完成
希尔排序是不稳定的,时间复杂度在O(n*logn)与O(n^2)之间
,比直接插入排序快
-------------------------------------------------
*/
/**
* 希尔排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void shell_sort(int a[], int n)
{
int t;
int i, j;
for(int d=n/2; d>=1; d /= 2) {
for(i=d; i<n; i++) {
//对每组进行插入排序
t = a[i];
for(j=i-d; j>=0; j -= d) {
if(t < a[j]) a[j+d] = a[j];
else
break;
}
a[j+d] = t;
}
}
}
/*
-------------------------------------------------
快速排序
算法思想:
通过一趟扫描后,以一个基准点的左边都比它小,右边都
比它大,又分别对左边和右边进行处理,直到左边和右边
只有一个元素
快速排序是不稳定的,最理想情况算法时间复杂度
O(nlogn),最坏O(n^2),解决办法为每次取中间的数为
基准点
-------------------------------------------------
*/
* 快速排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void quick_sort( int *a, int start, int end )
{
int i = start, j = end, t;
if( start < end )
{
t = a[start];
while( i < j )
{
while( i<j && a[j] > t ) //从后向前扫描
j--;
if( i<j )
{
a[i] = a[j];
i++;
}
while( i<j && a[i] < t ) //从前向后扫描
i++;
if( i<j )
{
a[j] = a[i];
j--;
}
}
a[i] = t; //把基准点放入争取位置
quick_sort( a, 0, i-1 );
quick_sort( a, i+1, end );
}
return;
}
/*
-------------------------------------------------
堆排序
算法思想:
堆排序是一种树形选择排序,堆的根元素为最大值,
完全二叉树能清楚表示堆
首先将元素看作顺序存储的二叉树,使其成为一个堆,
再将根元素与最后一个元素交换,再对前n-1个元素
构建堆,直到只有两个节点的堆
需要两个函数,一个是用于构建的堆的函数,一个是
调用此函数进行排序的函数
堆排序是不稳定的,O(nlogn)
-------------------------------------------------
*/
/**
* 构建堆
*
* @param a -[in,out] -需要构建的数组
*
* @param top -[in] -元素开始位置
*
* @param tail -[in] -元素结束位置
*
* @return -[None]
*/
void sift(int a[], int top, int tail)
{
if(top >= tail) return;
//将堆顶元素,向下筛选放入堆中 ,够成大根堆
int i = top;
int j = i*2+1; //i节点的左子节点
int t = a[i];
while(j <= tail) {
if(j+1 <= tail && a[j] < a[j+1]) j++;
if(t < a[j]) {
a[i] = a[j];
i = j;
j = j*2 + 1;
} else
break;
}
a[i] = t;
}
/**
* 堆排序
*
* @param a -[in,out] -需要排序的数组
*
* @param n -[in] -数组元素个数
*
* @return -[None]
*/
void heap_sort(int a[], int n)
{
//初始化堆
for(int i=n/2-1; i>=0; i--) {
sift(a, i, n-1);
}
for(int i=0; i<10; i++)
printf("%d ", a[i]);
printf("\n");
//循环n次,每次得到堆中最大值
for(int i=n-1; i>0; i--) {
int t = a[0];
a[0] = a[i];
a[i] = t;
sift(a, 0, i-1);
}
}
/*
-------------------------------------------------
归并排序
算法思想:
归并排序也是分治法,先将相邻元素分为n/2组,对每组
进行排序,再合并成n/4组,依次类推全部合并为一组
结束
归并排序是稳定的,O(nlogn)
-------------------------------------------------
*/
/**
* 合并两个序列
*
* @param a -[in,out] -需要构建的数组
*
* @param start -[in] -元素开始位置
*
* @param mid -[in] -序列分割位置
*
* @param end -[in] -元素结束位置
*
* @return -[None]
*/
void merge( int *a, int start, int mid, int end )
{
int i = start, j = mid;
queue<int> q; //利用队列来作为临时存放空间
while( i < mid && j < end )
{
if( a[i] < a[j] )
{
q.push( a[i] );
i++;
}
else
{
q.push( a[j] );
j++;
}
}
while( i < mid )
{
q.push( a[i] );
i++;
}
while( j < end )
{
q.push( a[j] );
j++;
}
//将在队列中排好序的元素赋值给数组
for( i=start; i<end; i++ )
{
a[i] = q.front();
q.pop();
}
}
/**
* 归并排序
*
* @param a -[in,out] -需要构建的数组
*
* @param start -[in] -元素开始位置
*
* @param mid -[in] -序列分割位置
*
* @param end -[in] -元素结束位置
*
* @return -[None]
*/
void merge_sort( int *a, int start, int end )
{
int mid;
if( start+1 < end )
{
mid = (start+end) / 2 ;
merge_sort( a, start, mid );
merge_sort( a, mid, end );
merge( a, start, mid, end );
}
}
/*
-----------------------------------------------------
基数排序
算法思想:
例如 m 位数的 n个整数,先根据个位数的值放入对应的桶中,
根据桶的顺序提取元素,再根据十位数的值放入对应的桶中,
以此类推
算法复杂度: O(m*n*10)
备注:如372,要得到百位数字:
372 % 1000 / (1000/10) = 3
-----------------------------------------------------
*/
void bucket_sort(int *a, int m, int n) {
queue<int> ques[10];
int mod = 1;
int count = 0;
int index = 0;
for(int i=0; i<m; i++) {
mod = mod*10;
//放入对应桶中
for(int j=0; j<n; j++) {
index = a[j] % mod / (mod/10); //计算位置上的数字
ques[index].push(a[j]);
}
count = 0;
//将桶中数据依次取出
for(int j=0; j<10; j++) {
while(!ques[j].empty()) {
a[count++] = ques[j].front();
ques[j].pop();
}
}
}
}