算法复习 - 分治法

前奏:
分治法可能是最著名的通用算法设计技术了:很多非常有效的算法实际上就是这个通用算法的特殊实现。

分治法主要按以下方案工作:
1.将一个问题划分为同一类型的若干子问题,子问题的规模最好相同。
2.对这些子问题求解(一般使用递归)
3.有必要的话,合并这些子问题的解,以得到原始答案。

分治法的流程见下图,该图描述的是将】一个问题分解成两个较小子问题的例子,也是最常见的情况。
在这里插入图片描述

对于分治法效率上的分析,有下列递推式(通用分治递推式
T(n) = aT(n / b) + f(n)

n表示这个实例规模,a表示其中有a个实例需要求解,b表示n个实例可以划分为b个规模为(n/b)的实例。f(n)是一个函数,表示将问题分解为小问题和将结果合并起来所消耗的时间。

在分析分治算法的效率时,我们可通过下列定理大大缩减分析的时间
在这里插入图片描述

分治法主要算法有合并排序,快排,二叉树的遍历及其相关特性,大整数乘法和Strassen矩阵乘法等等。

1.合并排序:对于一个需要排序的数组A【0 ~ n - 1】,合并排序把它一分为2:A【0 ~ [n/2] - 1】和A【[n/2] ~ n - 1】,并对每个子数组递归排序,然后把这两个排好序的数组合并成一个有序的数组。

上代码:

#include<iostream>

using namespace std;

const int maxn = 1001;
int i,j;

void Merge(int r[],int r1[],int s,int m,int t)
{
    i = s;j = m + 1;int k = s;
    while(i <= m&&j <= t)
    {
        if(r[i] <= r[j])r1[k ++] = r[i ++];
        else r1[k ++] = r[j ++];
    }
    if(i <= m)while(i <= m)
        r1[k ++] = r[i ++];
    else while(j <= t)
        r1[k ++] = r[j ++];
}

void MergeSort(int r[],int r1[],int s,int t)
{
    if(s == t)r1[s] = r[s];
    else {
        int m = (s + t) / 2;
        MergeSort(r,r1,s,m);
        MergeSort(r,r1,m + 1,t);
        Merge(r,r1,s,m,t);
    }
}

main()
{
   int r[maxn],r1[maxn];
   int n;
   cin>>n;
   for(i = 0;i < n;i ++)
   {
       cin>>r[i];
   }
   MergeSort(r,r1,0,n);
   for(i = 0;i < n;i ++)
    cout<<r1[i]<<" ";
}

2.快排:

#include<bits/stdc++.h>

using namespace std;

int scan(int i,int j);
void quickSort(int i,int j);

int num[10] = {1,32,4,12,4,5,63,21,2,6};

main()
{
    //num[20] = {1,32,4,12,4,5,63,21,2,6};
    //int len = strlen(num);
    quickSort(0,10);
    for(int i = 1;i <= 10;i ++)
       cout<<num[i]<<" ";
}

int scan(int i,int j)
{
    int tem;
    while(i < j)
    {
        while(i < j&&num[i] <= num[j])j --;
        if(i < j)
        {
            tem = num[j];
            num[j] = num[i];
            num[i] = tem;
            i ++;
        }
        while(i < j&&num[i] <= num[j])i ++;
        if(i < j)
        {
            tem = num[j];
            num[j] = num[i];
            num[i] = tem;
            j --;
        }
    }
    return i;
}

void quickSort(int i,int j)
{
    int mid;
    if(i < j)
    {
        mid = scan(i,j);
        quickSort(i,mid - 1);
        quickSort(mid + 1,j);
    }
}

3.二叉树的遍历:

#include<stdio.h>
#include<queue>
#include<bits/stdc++.h>//万能头文件,不建议用,太慢
#include<iostream>
using namespace std;

struct tree{
	char data;
	struct tree *lchild,*rchild;
};

int depth(tree*);//求二叉树的深度
void create(tree* &T);//创建树
int numNode(tree *T);//寻找有多少个节点
queue<tree>q;//层序遍历需要用的队列

void create(tree* &T)//创建二叉树 
{
	char c;
	scanf("%c",&c);
	if(c=='/') return;
	T=new tree;
	T->data=c;
	T->lchild=NULL;
	T->rchild=NULL;
	create(T->lchild);
	create(T->rchild); 
}

void priorOrder(tree* T)//先序遍历二叉树
{
	if(T)
	{
		cout<<T->data<<endl;
		priorOrder(T->lchild);
		priorOrder(T->rchild);
	}
} 

void behindOrder(tree* T)//后序遍历二叉树 
{
	if(T)
	{
		behindOrder(T->lchild);
		behindOrder(T->rchild);
		cout<<T->data<<endl;
	}
}

void midOrder(tree *T)//中序遍历二叉树 
{
	if(T)
	{
		midOrder(T->lchild);
		cout<<T->data<<endl;
		midOrder(T->rchild);
	}
}

void cengOrder(tree *T) //层序遍历二叉树 
{
	if(T)
	{
		q.push(*T);
	}
	while(!q.empty())
	{
		cout<<q.front().data;
		if (q.front().lchild != NULL)   //如果有左孩子,lchild入队列
        {
            q.push(*q.front().lchild);   
        }

        if (q.front().rchild != NULL)   //如果有右孩子,rchild入队列
        {
            q.push(*q.front().rchild);
        }
        q.pop();
        if(!q.empty()){
        	cout << " → ";
		}
	}
}

int numNode(tree* T)//计算节点个数
{
	int count=0;
	if(T)
	{
		++count;
		count+=numNode(T->lchild);
		count+=numNode(T->rchild);
	}
	return count;
} 

int depth(tree* T)//计算树的深度
{
	int leftLen,rightLen;
	if(T==NULL)return 0;
	else {
		leftLen=depth(T->lchild)+1;
		rightLen=depth(T->rchild)+1;
	}
	if(leftLen>rightLen)return leftLen;
	else return rightLen;
} 

int numLeaf(tree *T)//计算叶子节点的个数
{
	int num=0;
	if(T)
	{
		if(T->lchild==NULL&&T->rchild==NULL){
			++num;
		}
		num+=numLeaf(T->lchild);
		num+=numLeaf(T->rchild);
	}
    return num;
} 

int main()
{
     struct tree *T=new tree;
     T=NULL;
     cout<<"输入你要创建的二叉树:"<<endl;
     create(T);
     cout<<"节点的个数是:"<<numNode(T)<<endl;
     cout<<"树的节点深度:"<<depth(T)<<endl;
     cout<<"树的叶子节点数:"<<numLeaf(T)<<endl; 
     cout<<"先序遍历:"<<endl;   priorOrder(T);
	 cout<<endl;
	 cout<<"后续遍历:"<<endl;   behindOrder(T);
	 cout<<endl;
	 cout<<"中序遍历:"<<endl;   midOrder(T);
	 cout<<endl;
	 cout<<"层序遍历:"<<endl;   cengOrder(T);
	 cout<<endl; 
	 
	 return 0; 
}



4.大整数加法

# include <stdio.h>
# include <string.h>
# define N 205
int main ()
{
	char char1[205] = {0};
	char char2[205] = {0};
	int num1[N] = {0},num2[N] = {0},result[N] = {0},m,n,p,j;
	gets(char1);
	gets(char2);//输入两个字符串
	m = strlen(char1);
	n = strlen(char2);//求出两个字符串的长度
	for(int i = m - 1;i >= 0;i --){
		num1[m - 1 - i] = char1[i] - '0';
	}
	for(int i = n - 1;i >= 0;i --){
		num2[n - 1 - i] = char2[i] - '0';//将两个字符串的值赋给数组
	}
	for(int i = 0;i < 205;i ++){
		p = num1[i] + num2[i] + result[i + 1];
		result[i] = p % 10;
		result[i + 1] = p / 10;//将数组进行相加,%q表示这一位的数值大小,/q表示下一位的进位
	}
	j = 200;
	while(result[j] == 0&&j > 0){
		j --;//得到数组e[i]不为0的第一位
	}
	while(j > -1){
		printf("%d",result[j]);
		j --;//将e[i]逆序输出,最后一位即为最后结果的第一位
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值