实用算法的分析与程序设计——分治算法(归并排序,快速排序)

有许多算法在结构上是递归的:为了解决一个给定问题,算法要一次或多次地调用其自身来解决相关的子问题。这些算法通常采用分治策略:将原问题分成n个规模较小而结构与原问题相似的子问题。递归地解这些子问题,然后合并其结果就得到原问题的解。N=2时的分治法又称二分法。

用分治法求解一个问题,所需的时间是由子问题的个数,大小以及把这个问题分解为子问题所需的工作总量来确定的。一般来说,二分法(即把任意大小的问题尽可能的等分为两个子问题)较为有效。 

分治法在每一层递归上都有三个步骤:
分解:将原问题分解成一系列子问题;
解决:递归的解各子问题。若子问题足够小,则直接解
合并:将子问题的结果合并成原问题的解;

分治算法实例

快速排序

设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

合并排序

归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾

/*
 * =====================================================================================
 *
 *       Filename:  merge.cc
 *
 *    Description:  合并排序,快速排序
 *
 *        Version:  1.0
 *        Created:  05/25/2015 08:21:08
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  xiu, 
 *   Organization:  
 *
 * =====================================================================================
 */
#include<iostream>

using namespace std;

#define N 6

//输出测试
void out( int *list )
{

    cout << "\n_________________________________\n" << endl;

    for ( int i = 0 ; i < N ; i++ )
    {
        cout << list[i] << "\t" ;
    }

    cout << "\n_________________________________\n" << endl;
}

//将数组位置为q的元素插入到p位置的元素那
void insert(int *list, int p, int q )
{
    int temp = list[q];

    for( int i = q ; i >= p; i-- )
    {

        list[i] = list[ i-1 ];  

    }

    list[p] = temp;
}

//合并函数(将数组中q+1——r的元素插入到 p——q中)
void merge(int *list, int p, int q, int r)
{

    int i = p ,j = q + 1 ;

    while( j <= r )
    {
        while( i <= q )
        {
            if( list[i] >= list[j] )
            {
                insert( list, i, j );

                break;
            }
            else
            {
                i++;
            }
        }

        j++;

        i = p ; 

    }   
}

//合并排序 
//将list里面p 到 r顺序的数组排序
void merge_sort( int *list, int p, int r )
{



    if ( (r-p) >= 1 )
    {

        int q = ( p + r ) / 2 ;

        merge_sort( list , p , q ) ;

        merge_sort( list , q+1 , r ) ;

        merge(list, p, q, r);

        out( list );
    }
}


//交换p和q位置的列表中的值
void swap( int *list, int p, int q )
{
    int temp = list[p];
    list[p] = list[q];
    list[q] = temp;
}

//快速排序
void quick_sort( int *list, int start,int end )
{

    if( start > end )
    {

        return;
    }

    int low = start;
    int high = end;
    int key = list[ low ];

    while( low < high )
    {

        while(low < high && list[high] >= key )
        {
            high--;
        }
        list[low] = list[high];


        while(low < high && list[low] <= key )
        {
            low++;
        }
        list[high] = list[low];

    }

    list[low] = key;

    quick_sort(list, start, low-1 );

    quick_sort(list, low+1, end );
}

int main()
{
    int list[ N ] = { 5 , 8 , 3 , 4 , 9 , 2 } ;

    //merge_sort( list , 0 , N-1 ) ;  //合并排序

    quick_sort( list , 0, N-1 );    //快速排序

    out( list );

    return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值