数的因数分解问题困扰了我很长时间了,在看数据结构中的图的广度优先遍历的问题的时候,灵感突发,想出了具体算法,先就将算法进行介绍。
对一个数的因数分解,如10,如果我们对其从最小为1进行分解,那么首先就为1、9;然后再将9从最小为2开始分解(即将要分解7=9-2),分解为2、7,然后将7从最小为3开始分解(即将要分解4=7-3),分解为3、4;如果对4进行最小为4的分解(即将要分解0=4),但由于0<=4,则返回到7;然后对7进行最小为4开始的分解(即将要分解3=7-4),但由于7-4=3<4,所以继续返回到9;然后对9进行最小为3开始的分解。从上述过程我们可以看出,分解数是一个递归的过程。
10分解为1、9;然后对9进行从2开始的递归,递归的返回条件就是将要分解的数(我们假定为num)小于等于最小开始的数(我们假定为begin),如果没有等号,则分解10会出现5,5这样的结果。
具体算法实现中,我用到了双循环链表来的尾插法和只删除尾部元素来实现栈的结构(其实用数组是最好的,但为了联系链表就用链表了),不用单链表的原因是我们需要对栈进行从头遍历从而输出结果。
具体算法实现如下(c语言实现):
#include <stdio.h>
#include <malloc.h>
/**
*
*双循环队列的结构
*
*/
typedef struct DNode
{
int data;
struct DNode *pre,*next;
}DNode,*DLinkNode;
/**
*
*初始化双循环队列
*
*/
DNode *InitDLink(DNode *head)
{
head=(DNode *)malloc(sizeof(DNode));
head->data=0;
head->pre=head;
head->next=head;
}
/**
*
*用尾插法向栈中插入元素
*
*/
void Push(DNode *head,int data)
{
DLinkNode temp=(DNode *)malloc(sizeof(DNode));
temp->data=data;
temp->next=head->pre->next;
temp->pre=head->pre;
head->pre->next=temp;
head->pre=temp;
}
/**
*
*用尾插法从栈中删除元素
*
*/
void Pop(DNode *head)
{
if(head->next==head)
printf("pop end");
DLinkNode temp=head->pre;
head->pre=temp->pre;
temp->pre->next=head;
free(temp);
}
/**
*
*清楚栈中的元素(没有用到)
*
*/
void Clear(DNode *head)
{
while(head->next!=head)
{
DLinkNode temp=head->next;
head->next=temp->next;
temp->next->pre=head;
free(temp);
}
}
/**
*
*对栈从头遍历,输出分解结果
*
*/
void TraversalLink(DNode *head)
{
if(head==NULL)
printf("NULL");
DLinkNode temp=head->next;
while(temp!=head)
{
printf("%d\t",temp->data);
temp=temp->next;
}
printf("\n");
}
/**
*
*利用栈来分解数
*
*num:要分解的书;begin:开始的数(如10从1开始就是1,9;从2开始就是2,8)
*/
void NumberSolve(int num,int begin,DNode *head)
{
if(num<=begin)
{
return;
}
int i;
for(i=begin;i<num/2+num%2;/*奇偶数结束相差1,奇数比偶数多1,如11为5(11/2+11%2),6;10为4,6*/i++)
{
Push(head,i); //向栈中插入最小开始分解的数
Push(head,num-i); //向栈中插入减去最小开始分解的数(如10从1开始分解,就插入9=10-1)
TraversalLink(head); //输出栈中结果
Pop(head); //删除即将要分解的数
NumberSolve(num-i,i+1,head); //对即将要分解的书开始从上一个最小开始分解数加1的书开始分解
//Clear(head);
Pop(head); //删除以全部分解了的数
}
}
int main()
{
DNode *head=NULL;
head=InitDLink(head);
int num=11,begin=1; /*要分解的数和开始的数*/
NumberSolve(num,begin,head);
/*
*测试栈功能的代码(无用)
while(1)
{
int a;
scanf("%d",&a);
if(a==0)
break;
Push(head,a);
}
TraversalLink(head);
Clear(head);
TraversalLink(head);
*/
printf("end\n");
return 1;
}