排序第一站,插入排序与分治算法

翻开算法导论的第一章,可以算作是基本介绍吧,第二章开始介绍算法,本以为最开始会介绍冒泡排序。。。哈哈哈,结果很尴尬,最先介绍的就是今天要讲的第一个算法,

插入排序:

插入排序一个非常形象的例子就是扑克牌的插入,我们每次拿起一张新牌时,总是可以插入到合适的位置,因此可以将他的处理方式总结为每次拿起新牌时,从左开始向右依次比较,直至有牌比新的牌要小,则将牌插入到这张比它小的牌的后面,依次插入完所有的牌,那么排序也就完成了。插入排序的伪代码如下:

INSERITION_SORT(A)
1 for j = 2 to A.length
2     key = A[j]
3     //Insert A[j] into the sorted sequence A[1..j-1]
4     i = j - 1;
5     while i>0 and A[i]>key
6         A[i+1] = A[i]
7         i = i-1
8     A[i+1] = key

根据伪代码可以很方便地写出对应的C++代码如下:

//chapter2 插入算法
//插入排序将result数组进行排序
//输入:数组以及数组的元素个数,操作对象为数组result
//输出:无,只是对result进行排序
//insertion
void Isort::insertion_sort(int result[],int c)
{
    int key,i,arraycount;
    arraycount = c;
    if(arraycount > 1)
    {
        for(int j = 1; j1;
            while(i >= 0 && result[i] > key)
            {
                result[i+1] = result[i];
                i--;
            }
            result[i+1] = key;
        }
    }
    else
    {

    }
}

注意:伪代码中的下标是从1开始的,而我们在实际中操作数组时是从下标0开始的,因此在while的判断条件时伪代码是大于0,而C++代码中是大于等于0。

分治算法:

插入算法介绍完之后再介绍另一种算法,分治算法,这一算法虽然不是很出色,但是他的思想是很棒的,就是将一个大问题分解成两个类似于大问题的小问题,通过递归的思想来一步一步的求解,分治算法的伪代码如下:

MERGE_SORT(A,p,r)
1 if p < r
2     q = []{(p+r)/2} //表示不大于(p+r)/2的最大整数
3     MERGE_SORT(A,p,q)
4     MERGE_SORT(A,q+1,r)
5     MERGER(A,p,q,r)

其中合并函数的伪代码如下:

MERGE(A,p,q,r)
1 n1 = q - p + 1
2 n2 = r - q
3 Let L[1..n1+1] and R[1..n2+1] be new arrays
4 for i = 1 to n1
5     L[i] = A[p+i-1]
6 for j = 1 to n2
7     R[j] = A[q+j]
8 L[n1+1] = 正无穷大
9 R[n2+1] = 正无穷大
10 i = 1
11 j = 1
12 for k = p to r
13     if L[i] <= R[j]
14         A[k] = L[i]
15         i = i+1
16     else 
17         A[k] = R[j]
18         j = j+1

根据伪代码写出对应的C++代码如下:

//chapter2 分治算法
//分治法排序,采用分治法对数组进行排序
//输入:数组a,数组a的第一个元素的坐标p,最后一个元素的坐标r
//输出:无,操作后数组a为已经排列好的数组
//merge
void Isort::merge_sort(int a[], int p, int r)
{
    if(pint q = (p+r)/2;
        merge_sort(a,p,q);
        merge_sort(a,q+1,r);
        merge(a,p,q,r);
    }
}
//合并算法:在使用分治算法时需要调用的合并算法
//输入:数组a,元素下表p,q,r
//输出:无,功能是将数组a中排好序的两部分合二为一
void Isort::merge(int a[], int p, int q, int r)
{
    int n1,n2,i,j,k;
    int *L,*R;
    n1 = q - p + 1;
    n2 = r - q;
    L = (int *)malloc((sizeof(int))*n1);
    R = (int *)malloc((sizeof(int))*n2);
    for(i = 0 ; i < n1 ; i++)
    {
        L[i] = a[p+i];
    }
    for(i = 0 ; i < n2 ; i++)
    {
        R[i] = a[q+i+1];
    }
    i = 0;
    j = 0;
    for(k = p ; k < r+1 ; k++)
    {
        if((L[i] <= R[j] && i < n1) || (j >= n2))
        {
            a[k] = L[i];
            i = i+1;
        }
        else
        {
            a[k] = R[j];
            j = j+1;
        }
    }
    free(L);
    free(R);
}

需要注意的一点是在伪代码中放置了哨兵牌,即最后一张牌的大小是无穷大,然而在实际的代码中我们无法完成这一功能,因此可以根据i与n1的关系以及j与n2的关系来判断是否其中的一个数组已经全部合并完成,注意if的判断条件应该要怎么写。
到此为止,插入排序与分治算法的代码介绍完毕。

你可能感兴趣的:(排序第一站,插入排序与分治算法)