??xml version="1.0" encoding="utf-8" standalone="yes"?> 题目Q二叉树(wi)的结点定义如下:(x) TreeNode int m_nValue; TreeNode* m_pLeft;
TreeNode* m_pRight;
输入两棵二叉?/span>A?/span>BQ判断树(wi)B是不?/span>A的子l构?/span>
例如Q下图中的两|(wi)A?/span>BQ由?/span>A中有一部分子树(wi)的结构和B是一L(fng)Q因?/span>B是A的子l构?/span>
1 8
/ \ / \
8 7 9 2
/ \
9 2
/ \
4 7
分析Q这?/span>2010q微软校园招聘时的一道题目。二叉树(wi)一直是微Y面试题中l常出现的数据结构。对微Y有兴的读者一定要重点x二叉?wi)?/span>
回到q个题目的本w。要查找?/span>A中是否存在和?/span>Bl构一L(fng)子树(wi)Q我们可以分Z步:(x)W一步在?/span>A中找到和B的根l点的gL(fng)l点NQ第二步再判断树(wi)A中以N为根l点的子?wi)是不是包括和?wi)B一L(fng)l构?/span>
W一步在?/span>A中查找与根结点的gL(fng)l点。这实际上就是树(wi)的遍历。对二叉?wi)这U数据结构熟(zhn)的读者自然知道我们可以用递归的方法去遍历Q也可以用@环的Ҏ(gu)去遍历。由于递归的代码实现比较简z,面试时如果没有特别要求,我们通常都会(x)采用递归的方式。下面是参考代码:(x)
HasSubtree(TreeNode* pTreeHead1, TreeNode* pTreeHead2)
if((pTreeHead1 == NULL && pTreeHead2 != NULL) ||
(pTreeHead1 != NULL && pTreeHead2 == NULL))
return false;
if(pTreeHead1 == NULL && pTreeHead2 == NULL)
return true;
return HasSubtreeCore(pTreeHead1, pTreeHead2);
HasSubtreeCore(TreeNode* pTreeHead1, TreeNode* pTreeHead2)
bool result = false;
if(pTreeHead1->m_nValue == pTreeHead2->m_nValue)
{
result = DoesTree1HaveAllNodesOfTree2(pTreeHead1, pTreeHead2);
}
if(!result && pTreeHead1->m_pLeft != NULL)
result = HasSubtreeCore(pTreeHead1->m_pLeft, pTreeHead2);
if(!result && pTreeHead1->m_pRight != NULL)
result = HasSubtreeCore(pTreeHead1->m_pRight, pTreeHead2);
return result;
在上qC码中Q我们递归调用hasSubtreeCore遍历二叉?/span>A。如果发现某一l点的值和?/span>B的头l点的值相同,则调?/span>DoesTree1HaveAllNodeOfTree2Q做W二步判断?/span>
在面试的时候,我们一定要注意边界条g的检查,x查空指针。当?/span>A或树(wi)B为空的时候,定义相应的输出。如果没有检查ƈ做相应的处理Q程序非常容易崩溃,q是面试旉常忌讳的事情。由于没有必要在每一ơ递归中做边界查(每一ơ递归都做查,增加了不必要的时间开销Q,上述代码只在HasSubtree中作了边界检查后Q在HasSubtreeCore中作递归遍历?/span>
接下来考虑W二步,判断以树(wi)A中以N为根l点的子?wi)是不是和?wi)Bh相同的结构。同P我们也可以用递归的思\来考虑Q如果结?/span>N的值和?/span>B的根l点不相同,则以N为根l点的子?wi)和?/span>B肯定不具有相同的l点Q如果他们的值相同,则递归地判断他们的各自的左右结点的值是不是相同。递归的终止条件是我们到达了树(wi)A或者树(wi)B的叶l点。参考代码如下:(x)
DoesTree1HaveAllNodesOfTree2(TreeNode* pTreeHead1, TreeNode* pTreeHead2)
if(pTreeHead2 == NULL)
return true;
if(pTreeHead1 == NULL)
return false;
if(pTreeHead1->m_nValue != pTreeHead2->m_nValue)
return false;
return DoesTree1HaveAllNodesOfTree2(pTreeHead1->m_pLeft, pTreeHead2->m_pLeft) &&
DoesTree1HaveAllNodesOfTree2(pTreeHead1->m_pRight, pTreeHead2->m_pRight);
博主何v涛对本博客文章n有版权。网l{载请注明出处http://zhedahht.blog.163.com/?/font>
遗传法QGenetic Algorithm, GAQ是q几q发展v来的一U崭新的全局优化法?962q霍兰d(Holland)教授首次提出了GA法的思想Q它借用了仿真生物遗传学和自焉择机理Q通过自然选择、遗传、变异等作用机制Q实现各个个体的适应性的提高。从某种E度上说遗传法是对生物q化q程q行的数学方式仿真?/p>
q一点体C自然界中"物竞天择、适者生?q化q程。与自然界相|遗传法Ҏ(gu)解问题的本n一无所知,它所需要的仅是对算法所产生的每个染色体q行评h(hun),把问题的解表C成染色体,q基于适应值来选择染色体,佉K应性好的染色体有更多的J殖Z(x)。在法中也x以二q制~码的串。ƈ且,在执行遗传算法之前,l出一染色体Q也x假设解。然后,把这些假设解|于问题?#8220;环境”中,也即一个适应度函C来评仗ƈ按适者生存的原则Q从中选择适应环境的染色体q行复制, 淘汰低适应度的个体Q再通过交叉Q变异过E生更适应环境的新一代染色体。对q个新种进行下一轮进化,臛_最适合环境的倹{?/p>
遗传法已用于求解带有应用前景的一些问题,例如遗传E序设计、函C化、排序问题、h工神l网l、分cȝl、计机囑փ处理和机器hq动规划{?/p>
׃遗传法是由q化论和遗传学机理而生的搜烦法Q所以在q个法中会(x)用到很多生物遗传学知识,下面是我们将?x)用来的一些术语说明:(x)
一、染色体(Chronmosome)
染色体又可以叫做基因型个?individuals),一定数量的个体l成了群?population),体中个体的数量叫做体大小?/p>
二、基?Gene)
基因是串中的元素Q基因用于表CZ体的特征。例如有一个串SQ?011Q则其中?Q?Q?Q?q?个元素分别称为基因。它们的值称为等位基?Alletes)?/p>
三、基因地?Locus)
基因地点在算法中表示一个基因在串中的位|称为基因位|?Gene Position)Q有时也U基因位。基因位|由串的左向双,例如在串 SQ?101 中,0的基因位|是3?/p>
四、基因特征?Gene Feature)
在用串表C整数时Q基因的特征g二进制数的权一_(d)例如在串 S=1011 中,基因位置3中的1Q它的基因特征gؓ(f)2Q基因位|?中的1Q它的基因特征gؓ(f)8?/p>
五、适应?Fitness)
各个个体对环境的适应E度叫做适应?fitness)。ؓ(f)了体现染色体的适应能力Q引入了寚w题中的每一个染色体都能q行度量的函敎ͼ叫适应度函? q个函数是计个体在体中被使用的概率?/p>
霍兰?Holland)教授最初提出的法也叫单遗传算法,单遗传算法的遗传操作主要有三U:(x)选择(selection)、交?crossover)、变?mutation)q也是遗传算法中最常用的三U算法:(x)
1Q选择(selection)
选择操作也叫复制操作Q从体中按个体的适应度函数值选择适应环境的个体。一般地_(d)选择适应度高的个体繁D下一代的数目较多Q而适应度较?yu)的个体Q繁D下一代的数目较少,甚至被淘汰。最通常的实现方法是轮盘?roulette wheel)模型。o(h)Σfi表示体的适应度gdQfi表示U群中第i个染色体的适应度|它被选择的概率正好ؓ(f)光应度值所占䆾额fiQ?#931;fi。如下图表中的数据适应值dΣfi=6650,适应度ؓ(f)2200变选择的可能ؓ(f)fiQ?#931;fi=2200/6650=0.394.
Fitness |(x) | 2200 | 1800 | 1200 | 950 | 400 | 100 |
选择概率Q?/td> | 3331 | 0.271 | 0.18 | 0.143 | 0.06 | 0.015 |
2Q交?Crossover)
交叉子被选中的两个个体的基因链按一定概率pcq行交叉Q从而生成两个新的个体,交叉位置pc是随机的。其中Pc是一个系l参数。根据问题的不同Q交叉又Z单点交叉子QSingle Point CrossoverQ、双点交叉算子(Two Point CrossoverQ、均匀交叉子 (Uniform Crossover)Q在此我们只讨论单点交叉的情c(din)?/p>
单点交叉操作的简单方式是被选择出的两个个体S1和S2作ؓ(f)父母个体Q将两者的部分基因码D行交换。假讑֦下两?位的个体Q?/p>
|
产生一个在1?之间的随机数cQ假如现在生的?Q将S1和S2的低二位交换QS1的高六位与S2的低六位l成C10001100Q这是S1和S2 的一个后代P1个体QS2的高六位与S1的低二位l成C11101111Q这是S1和S2的一个后代P2个体。其交换q程如下图所C:(x)
Crossover | 11110000 | Crossover | 11110000 |
---|---|---|---|
S1 | 1000 1111 | S2 | 1110 1100 |
P1 | 1000 1100 | P2 | 1110 1111 |
3Q变?Mutation)
q是在选中的个体中Q将C体的基因铄各位按概率pmq行异向转化Q最单方式是改变串上某个位置数倹{对二进制编码来说将0?互换Q?变异?Q?变异??/p>
如下8位二q制~码Q?/p>
|
随机产生一??之间的数iQ假如现在k=6Q对从右往左的W?位进行变异操作,原来的1变ؓ(f)0Q得到如下串Q?/p>
|
整个交叉变异q程如下图:(x)
4Q精׃?QElitismQ?/strong>
仅仅从生的子代中选择基因L造新的种可能会(x)丢失掉上一代种中的很多信息。也是说当利用交叉和变异生新的一代时Q我们有很大的可能把在某个中间步骤中得到的最优解丢失。在此我们用精׃义(ElitismQ方法,在每一ơ生新的一代时Q我们首先把当前最优解原封不动的复制到新的一代中Q其他步骤不变。这样Q何时M生的一个最优解都可以存?gu)zd遗传法l束?/p>
上述各种子的实现是多种多样的,而且许多新的子正在不断地提出,以改qGA某些性能。比如选择法q有分均衡选择{等?/p>
说简单点遗传法是遍历搜烦I间或连接池Q从中找出最优的解。搜索空间中全部都是个体Q而群体ؓ(f)搜烦I间的一个子集。ƈ不是所有被选择了的染色体都要进行交叉操作和变异操作Q而是以一定的概率q行Q一般在E序设计中交叉发生的概率要比变异发生的概率选取得大若干个数量。大部分遗传法的步骤都很类|怋用如下参敎ͼ(x)
Fitness函数Q见上文介绍?/p>
FitnessthresholdQ适应度阀|Q适合度中的设定的阀|当最优个体的适应度达到给定的阀|或者最优个体的适应度和体适应度不再上升时(变化率ؓ(f)?Q则法的P代过E收敛、算法结束。否则,用经q选择、交叉、变异所得到的新一代群体取代上一代群体,q返回到选择操作处l@环执行?/p>
PQ种的染色体L叫种规模,它对法的效率有明显的媄响,光度等于它包含的个体数量。太时难以求出最优解Q太大则增长收敛旉DE序q行旉ѝ对不同的问题可能有各自适合的种规模,通常U群规模?30 ?160?/p>
pcQ在循环中进行交叉操作所用到的概率。交叉概率(PcQ一般取0.6?.95之间的|Pc太小旉以向前搜索,太大则容易破坏高适应值的l构?/p>
PmQ变异概率,从个体群中生变异的概率Q变异概率一般取0.01?.03之间的值变异概率Pm太小旉以生新的基因结构,太大佉K传算法成了单U的随机搜烦?/p>
另一个系l参数是个体的长度,有定长和变长两种。它对算法的性能也有影响。由于GA是一个概率过E,所以每ơP代的情况是不一L(fng),pȝ参数不同QP代情况也不同?/p>
了解了上面的基本参数Q下面我们来看看遗传法的基本步骤?/p>
基本q程为:(x)
E序的停止条件最单的有如下二U:(x)完成了预先给定的q化代数则停止;U群中的最优个体在q箋若干代没有改q或q_适应度在q箋若干代基本没有改q时停止?/p>
Ҏ(gu)遗传法思想可以d如右图所C的单遗传算法框图:(x)
下面伪代码简单说明了遗传法操作q程Q?/p>
|
能有效实现遗传算法的应用例子有很多,像西z双陆棋、国际名模等{都是遗传程序设计学?fn)的工具Q但?Robocode 有着其他几个无可比拟的优势:(x)
?Robocode 中其实有很多U遗传算法方法来实现q化机器人,从全世界?Robocode 派中也发展几种比较成熟的方法,比如预设{略遗传、自开发解释语a遗传、遗传移动我们就q几U方法分别加以介l。由于遗传算法操作过E都cMQ所以前面二部分都是一些方法的介绍和部分例子讲解,后面部分?x)给Z用了遗传法的移动机器hZ子。在附录中,也提供了机器Z库中有关遗传法机器人的下蝲Q大家可参考?/p>
![]() ![]() |
![]() |
Robocode 坦克机器人所有行为都M开如移动、射凅R扫描等基本操作。所以在此把q些基本操作所用到的策略分别进化如下编码:(x)Ud{略move-strategy (MS), 子弹能量bullet-power-strategy (BPS), 雯扫描radar-strategy (RS), 和瞄准选择{略target- strategy (TS)。由于Robocode爱好者社的发展Q每一U基本操作都发展了很多比较成熟的{略Q所有在此我们直接在下面预先定义的这些策略如下表Q?/p>
MS | BPS | RS | TS |
---|---|---|---|
random | distance-based | always-turn | HeadOn |
Linear | light-fast | target-focus | Linear |
circular | Powerful-slow | target-scope-focus | Circular |
Perpendicular | Medium | nearest robot | |
arbitary | hit-rate based | Log | |
anti gravity | Statistic | ||
Stop | Angular | ||
Bullet avoid | wave | ||
wall avoid | |||
track | |||
Oscillators |
下面是基本移动策略的说明Q?/p>
瞄准{略说明如下Q?/p>
坦克的主要都定义在一个主循环中,我们在程序中定义Z面四个策略定义四U战略如Move,Radar,Power,TargetQ当某一事g发生Q基于这个事件而定的行为就?x)触发。而每个战略中都有不同的行为处理方式。这些行为通过遗传法触发Q遗传算法将调用q些基本动作q搜索这些策略的最佳组合。基于这些基本动作将?224 (=4*11*4*3*8)U可能发生。在Robocode AdvancedRobot cM有如下的Ud函数Q?/p>
下面?doMove UdҎ(gu)中用部分程序代码:(x)
RandomQ?/p>
|
LinearQ?/p>
|
CircularQ?/p>
|
anti gravityQ?/p>
|
q里我们用遗传算法来控制机器人移动位|。这些策略是Z下面几点Q机器hq位置、速度和方?Ҏ(gu)的位|(x,y坐标Q、速度、方位以?qing)相对?所有机器h和子弹位|,方位?qing)速度;场地大小{参数?/p>
当上面的信息在下一回移动中使用ӞZ对坐标|Ҏ(gu)q对坐标在Robocodep得到距离和角度。要惌Ud实现遗传必须要让它实现在U学?fn)?x)所以我们的代码必须做下面几件事Q要有一个函数收集适应度|在Robocodeq行q程中要q用到遗传操作,遗传后代要在Robocodeq行中生,而不是事后由手写入代码?/p>
本例中遗传算法ؓ(f)实现Ud用到两个cGA和MovePattern。此处的GA比较单主要完成数据和体的定义,以及(qing)q些定义的读写文件操作。基中包括如下参敎ͼ(x)体大小、交叉概率、变异概率、精英概率(既告诉从当前体C一代中有多移动不需要改变)、方E式中用的加权pL大小Q它通过一个主循环完成MovePattern的封装。MovePatterncM实现交叉、变异方法等Ҏ(gu)Q完成移动模式操作。而所有的输出保存在一个vector函数当中。Vector函数拥有一对实数数l,一个用于计x坐标Q另一个用于计y坐标。通过对x,y坐标的计,从而得到距R角度等|q生相在Ud{略。如下,MovePattern包含三个参数Qgrad表示vector函数排列序Qinput卌C算法给出的输入~号Qrang是加权的范围?/p>
|
交叉操作Q每一个交叉操作执行如下步骤,先在交叉操作中生一个特征码。这个特征码是个0?之间的变量数l。有关交叉的基本原理可参考上面部分。最后通过遍历vector函数Q把相应的加权D行交叉操作?/p>
|
q里的变异操作比较简单。把加权范围内的随机数值去代替0到数l长之间的随机数q保存到Ud模式中。则完成整个数组的变异过E:(x)
|
从上面的例子我们知道了遗传算法的大概实现Q但q没有告诉我们这些组件是如何一起工作的。当Robocode开始时Q如果文件中没有数据Q所以系l会(x)依照输入的策略随机生成一个移动模式,如果文g中有数据Q则加蝲q些数据。每一个移动模式在开始都?x)给Z一个适应度倹{当所有的Ud模式都接收到适应度|q完成各自的~号后,下面的操作将开始执行:(x)
适应度值在q行q算q程中由机器人程序不断调_(d)以找到最优适应度?/p>
限于副其他的一些策略本文不与详l说明,上面所有提到的{略和行为程序都可在|上或IBM的开发杂志上扑ֈ成熟的讲解和例子机器人。有兴趣的朋友可以把q些{略都加入到自己的遗传算法中来。我们取体大小?0Q选择概率?.7Q交叉概率ؓ(f)0.6Q变异概率ؓ(f)0.3Q与Robocode部分例子机器人测试,l过150代后你会(x)发现pȝ产生了很多有的{略。比如撞ȝ略,q些{略都不在我们定义的{略之中?/p>
![]() ![]() |
![]() |
遗传法可被看做L基因l字W串。但是你必须军_q些字符所代表的意义,也就是说如何解释每一个基因组。最单的Ҏ(gu)是把每一个基因组视ؓ(f)java代码Q编译ƈq行它们。但是这些程序编译都很困难,所以也有可能不能工作。Jacob Eisenstein设计了一U机器翻译语aTableRex来解册个问题。在java中,TableRex被用于进化和解释动行时的Robocode 机器人。通过试Q只要我把TableRex解释E序作ؓ(f)文g攑օRobocode控制器目录中Q这些控制器׃(x)d文gq开始战斗。TableRex是一些最适合遗传法的二q制~程。只要符合TableRexE序文法Q每个程序都能被解释?/p>
下表中显CZTableRex~码l构Q它׃个行动作函数Q二个输入和一个输出组成。如?的?Q这是个布尔型的表达?#8220;?line4 于 90”Q这个结果会(x)在最后一行输出布?yu)(dng)?f)1的倹{?/p>
Function | Input 1 | Input 2 | Output |
---|---|---|---|
1. Random | ignore | ignore | 0,87 |
2. Divide | Const_1 | Const_2 | 0,5 |
3. Greater Than | Line 1 | Line 2 | 1 |
4. Normalize Angle | Enemy bearing | ignore | -50 |
5. Absolute Value | Line 4 | ignore | 50 |
6. Less Than | Line 4 | Const_90 | 1 |
7. And | Line 6 | Line 3 | 1 |
8. Multiply | Const_10 | Const_10 | 100 |
9. Less Than | Enemy distance | Line 8 | 0 |
10. And | Line 9 | Line 7 | 0 |
11. Multiply | Line 10 | Line 4 | 0 |
12 Output | Turn gun left | Line 11 | 0 |
1.直接插入排序
原理Q将数组分ؓ(f)无序区和有序Z个区Q然后不断将无序区的W一个元素按大小序插入到有序区中去Q最l将所有无序区元素都移动到有序区完成排序?/span>
要点Q设立哨兵,作ؓ(f)临时存储和判断数l边界之用?/span>
实现Q?/span>
Void InsertSort(Node L[],int length)
{
Int i,j;//分别为有序区和无序区指针
for(i=1;i<length;i++)//逐步扩大有序?/span>
{
j=i+1;
if(L[j]<L[i])
{
L[0]=L[j];//存储待排序元?/span>
While(L[0]<L[i])//查找在有序区中的插入位置Q同时移动元?/span>
{
L[i+1]=L[i];//Ud
i--;//查找
}
L[i+1]=L[0];//元素插?/span>
}
i=j-1;//q原有序区指?/span>
}
}
2.希尔排序
原理Q又U增量羃?yu)排序。先序列按增量划分为元素个数相同的若干l,使用直接插入排序法进行排序,然后不断~小增量直至?span style="LINE-HEIGHT: 21px; FONT-FAMILY: 'Times New Roman'">1Q最后用直接插入排序完成排序?/span>
要点Q增量的选择以及(qing)排序最l以1为增量进行排序结束?/span>
实现Q?/span>
Void shellSort(Node L[],int d)
{
While(d>=1)//直到增量~小?
{
Shell(L,d);
d=d/2;//~小增量
}
}
Void Shell(Node L[],int d)
{
Int i,j;
For(i=d+1;i<length;i++)
{
if(L[i]<L[i-d])
{
L[0]=L[i];
j=i-d;
While(j>0&&L[j]>L[0])
{
L[j+d]=L[j];//Ud
j=j-d;//查找
}
L[j+d]=L[0];
}
}
}
交换排序
1.冒排序
原理Q将序列划分为无序和有序区,不断通过交换较大元素x序区֮成排序?/span>
要点Q设计交换判断条Ӟ提前l束以排好序的序列@环?/span>
实现Q?/span>
Void BubbleSort(Node L[])
{
Int i ,j;
Bool ischanged;//设计跛_条g
For(j=n;j<0;j--)
{
ischanged =false;
For(i=0;i<j;i++)
{
If(L[i]>L[i+1])//如果发现较重元素向后移?/span>
{
Int temp=L[i];
L[i]=L[i+1];
L[i+1]=temp;
Ischanged =true;
}
}
If(!ischanged)//若没有移动则说明序列已经有序Q直接蟩?/span>
Break;
}
}
2.快速排?/span>
原理Q不断寻找一个序列的中点Q然后对中点左右的序列递归的进行排序,直至全部序列排序完成Q用了分治的思想?/span>
要点Q递归、分?/span>
实现Q?/span>
选择排序
1.直接选择排序
原理Q将序列划分为无序和有序区,L无序Z的最值和无序区的首元素交换,有序区扩大一个,循环最l完成全部排序?/span>
要点Q?/span>
实现Q?/span>
Void SelectSort(Node L[])
{
Int i,j,k;//分别为有序区Q无序区Q无序区最元素指?/span>
For(i=0;i<length;i++)
{
k=i;
For(j=i+1;j<length;j++)
{
If(L[j]<L[k])
k=j;
}
If(k!=i)//若发现最元素,则移动到有序?/span>
{
Int temp=L[k];
L[k]=L[i];
L[i]=L[temp];
}
}
}
2.堆排?/span>
原理Q利用大根堆或小根堆思想Q首先徏立堆Q然后将堆首与堆交换,堆尾之后为有序区?/span>
要点Q徏堆、交换、调整堆
实现Q?/span>
Void HeapSort(Node L[])
{
BuildingHeap(L);//建堆Q大根堆Q?/span>
For(int i=n;i>0;i--)//交换
{
Int temp=L[i];
L[i]=L[0];
L[0]=temp;
Heapify(L,0,i);//调整?/span>
}
}
Void BuildingHeap(Node L[])
{ For(i=length/2 -1;i>0;i--)
Heapify(L,i,length);
}
归ƈ排序
原理Q将原序列划分ؓ(f)有序的两个序列,然后利用归ƈ法q行合ƈQ合q之后即为有序序列?/span>
要点Q归q、分?/span>
实现Q?/span>
Void MergeSort(Node L[],int m,int n)
{
Int k;
If(m<n)
{
K=(m+n)/2;
MergeSort(L,m,k);
MergeSort(L,k+1,n);
Merge(L,m,k,n);
}
}
基数排序
原理Q将数字按位数划分出n个关键字Q每ơ针对一个关键字q行排序Q然后针Ҏ(gu)序后的序列进行下一个关键字的排序,循环x有关键字都用过则排序完成?/span>
要点Q对关键字的选取Q元素分配收集?/span>
实现Q?/span>
Void RadixSort(Node L[],length,maxradix)
{
Int m,n,k,lsp;
k=1;m=1;
Int temp[10][length-1];
Empty(temp); //清空临时I间
While(k<maxradix) //遍历所有关键字
{
For(int i=0;i<length;i++) //分配q程
{
If(L[i]<m)
Temp[0][n]=L[i];
Else
Lsp=(L[i]/m)%10; //定关键?/span>
Temp[lsp][n]=L[i];
n++;
}
CollectElement(L,Temp); //攉
n=0;
m=m*10;
k++;
}
}