分治,利用递归的方法

1、hanota问题

问题描述:

在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子

代码实现:

#include<stdio.h>
#include<stdlib.h>

#define MAX_SIZE 14

typedef struct SeqStack
{
    int size;
    int top;
    int* data;
}mystack;

mystack* creatSeqStack(int size, int* arr)
{
    mystack* s = (mystack*)malloc(sizeof(mystack));
    s->data = (int*)malloc(sizeof(int) * MAX_SIZE);

    s->size = size;
    s->top = size - 1;
    for (int i = 0; i < size; i++)
        s->data[i] = arr[i];

    return s;
}

void pushstack(mystack* s, int val)
{
    if (s->top == MAX_SIZE - 1)
        return;
    s->top++;
    s->data[s->top] = val;

}


int popstack(mystack* s)
{
    if (s->top == -1)
    {
        return -1;
    }
    int r = s->data[s->top];
    s->top--;
    s->size--;
    return r;
}

void move(int num, mystack* s1, mystack* s2, mystack* s3)
{
    if (num == 1)
    {
        pushstack(s3, popstack(s1));
        return;
    }

    move(num - 1, s1, s3, s2);
    pushstack(s3, popstack(s1));
    move(num - 1, s2, s1, s3);
}


void hanota(int* A, int ASize, int* B, int BSize, int** C, int* CSize)
{
    mystack* s1 = creatSeqStack(ASize, A);
    mystack* s2 = creatSeqStack(BSize, B);
    mystack* s3 = creatSeqStack((*CSize), (*C));
    move(ASize, s1, s2, s3);
    *C = s3->data;
    *CSize = s3->size;
}

根据问题的描述,我们选择栈来存储数据(这是根据栈的性质:只能从栈顶进和出)。我们先将n-1个圆盘通过第三个柱子移动到第二个柱子上,再将最后一个圆盘移动到柱子三,再将n-1个柱子通过柱子一移动到柱子三,这样就实现了圆盘的移动。当然,这里是递归的定义,因此我们选择递归的方式。具体的说,就是将最大的那个圆盘移动到第三个柱子上,然后倒数第二大,倒数第三大......直到全部移动到第三个柱子上。这就是利用分治的思想,将规模为n的问题转化为规模为n-1的问题。这里分析一下,是否满足分治策略的条件:1)规模小到一定程度就可以很容易的解决,即第一个柱子上只有一个圆盘的时候。2)问题可以分解为若干个规模较小的相同问题,显然在这里也是可以的。3)利用该问题分解出的子问题的解可以合并成这个问题的解,在递归过程中实现了子问题解的合并,因此也是可行的。4)各个子问题是相互独立的,也显然成立。

2、二分查找

代码实现:

#include<stdio.h>
#include<stdbool.h>

bool bisearch(int* arr, int val,int right,int left);

int main()
{
	int arr[] = { 23,43,54,78,98,103,438,2005,85 };
	int len = sizeof(arr) / sizeof(int);
	if (bisearch(arr, 83, len - 1, 0))
		printf("找到了!\n");
	else
		printf("没找到!\n");
	return 0;
}


bool bisearch(int* arr, int val,int right,int left)
{
	if (right < left)
		return false;
	else
	{
		int mid = (right + left) / 2;
		if (val == arr[mid]) return  true;
		else if (val < arr[mid])
			bisearch(arr, val, mid - 1, left);
		else
			bisearch(arr, val, right, mid + 1);
	}

}

我们找到递归边界就是right<left,这样没有一个元素,故就是没找到。剩下的就是不断调用bisearch函数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值