日常记录:《算法导论》学习笔记之二

  在《算法导论》中还提到了合并算法,该算法采用分治法(divide-and-conquer)的思想。再次以整理扑克牌为例说明,当一堆杂乱无序的牌堆分为有序的两堆,比较两堆牌最上面的一张,按从小到大的方式合并起来,最后得到的一定是有序的,但由一堆无序的牌分为两堆时,所得到的仍旧是杂乱无序的,我们可以依次下去,直到最小的牌堆中只有一张牌时,此时是绝对有序的,然后依次合并,最后得到整理好的牌,这种算法称为合并算法。

  在设计算法时,为了“监视”合并时纸牌不会“越界”,在每个牌堆末设置“哨兵(sentinel)”牌,其伪代码如下:

MERGE(A, p, q, r)
n1 = q - p + 1
n2 = r - q
L[n1+1], P[n2+1]
for i : 0 to n1-1
  L[i] = A[p+i-1]
for j : 0 to n2-1
  R[j] = A[q+j]
L[n1+1] = ∞
R[n2+1] = ∞
i = 0
j = 0
for k : p to r
  if L[i] <= R[j]
    A[k] = L[i]
    i++
  else
    A[k] = R[j]
    j++
  给定一组实例,用C++实现合并算法如下:

#include 
   
   
    
    

void MergeSort(int A[], int p, int q);

int main(void)
{
    int A[20] = {5, 2, 4, 6, 1,
                 3, 15, 12, 14, 16,
                 11, 13, 8, 9, 7,
                 10, 18, 19, 17, 20};

    int left = 20 / 2;
    int right = 20 - left;
    MergeSort(A, left, right);
    for (int i = 0; i < 20; i++)
        std::cout << A[i] << " ";

    return 0;
}

void MergeSort(int A[], int p, int q)
{
    int n1 = p;
    int n2 = q;
    int L[n1 + 1];
    int R[n2 + 1];
    for (int i = 0; i < n1; i++)
        L[i] = A[i];
    for (int i = 0; i < n2; i++)
        R[i] = A[i + p];
    L[n1] = 999;
    R[n2] = 999;
    if (n1 != 1)
    {
        int left = n1 / 2;
        int right = n1 - left;
        MergeSort(L, left, right);
    }
    if (n2 != 1)
    {
        int left = n2 / 2;
        int right = n2 - left;
        MergeSort(R, left, right);
    }
    int i = 0;
    int j = 0;
    for (int k = 0; k < p + q; k++)
    {
        if (L[i] <= R[j])
        {
            A[k] = L[i];
            i++;
        }
        else
        {
            A[k] = R[j];
            j++;
        }
    }
}
   
   
  在章节练习中,提到将sentinel card除去,当合并的两个牌堆中任意一个没有牌时,将另一个牌堆直接放到合并牌后,笔者使用自己的想法实现,代码如下,如果有更好的欢迎提出交流:

#include 
   
   
    
    

void MergeSort(int A[], int p, int q);

int main(void)
{
    int A[8] = {3, 41, 26, 52, 38, 57, 9, 49};
    int left = 8 / 2;
    int right = 8 - left;
    MergeSort(A, left, right);
    for (int i = 0; i < 8; i++)
        std::cout << A[i] << " ";

    return 0;
}

void MergeSort(int A[], int p, int q)
{
    int n1 = p;
    int n2 = q;
    int L[n1 + 1];
    int R[n2 + 1];
    for (int i = 0; i < n1; i++)
        L[i] = A[i];
    for (int i = 0; i < n2; i++)
        R[i] = A[i + p];
    if (n1 != 1)
    {
        int left = n1 / 2;
        int right = n1 - left;
        MergeSort(L, left, right);
    }
    if (n2 != 1)
    {
        int left = n2 / 2;
        int right = n2 - left;
        MergeSort(R, left, right);
    }
    int i = 0;
    int j = 0;
    for (int k = 0; k < p + q; k++)
    {
        if (L[i] <= R[j])
        {
            A[k] = L[i];
            i++;
            while(i == n1 && j < n2)
                A[++k] = R[j++];
        }
        else
        {
            A[k] = R[j];
            j++;
            while(j == n2 && i < n1)
                    A[++k] = L[i++];
        }
    }
}
   
   
  除此之外,练习中还提到了一种排序算法,冒泡排序,其思路是依次比较相邻两个元素大小,符合筛选条件的交换位置,就好像吐泡泡一样,每次遍历从最末尾开始,结束时将最小或者最大的放到前面。给定一组实例,C++编程实现如下:
#include 
    
    
     
     

int main(void)
{
    int A[6] = {5, 3, 2, 4, 1, 6};
    int temp= 0;
    
    for (int i = 0; i < 6; i++)
    {
        for (int j = 5; j > i; j--)
        {
            if (A[j] < A[j - 1])
            {
                temp = A[j];
                A[j] = A[j - 1];
                A[j - 1] = temp;
            }
        }
    }
    for (int i = 0; i < 6; i++)
        std::cout << A[i] << " ";
        
    return 0;
}
    
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值