基本排序全解

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();
            }
        } 
    } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值