當前位置:首頁 » 操作系統 » 非遞歸演算法

非遞歸演算法

發布時間: 2023-03-23 03:46:20

Ⅰ 二叉樹非遞歸演算法利用哪種數據結構

二叉樹非遞歸演算法利用遞歸演算法數據結構。二叉樹遍歷演算法都採用的是遞歸演算法,遞歸演算法雖然結構簡潔,但在時空開銷上相對較大悄隱高,從而導致運行效率較低,並且有些程序設攜物計環境不支持遞歸,這就啟尺要求將遞歸演算法轉換成非遞歸演算法。

Ⅱ 編寫 快速排序的非遞歸演算法

終於編寫出來了,我寫了兩種,你看看:下面是代碼:

/*非遞歸演算法1
遞歸演算法的開銷很大,告盯所以在下編了一個非遞歸的,演算法描述如下:
A non-recursive version of quick sort using stack:
There are 2 stacks, namely one which stores the start of
a subarray and the other which stores the end of the
subarray.
STEP 1: while the subarray contains more than one element
,i.e. from Do {
SUBSTEP 1. pivot=Partion(subarray);
SUBSTEP 2. keep track of the right half of the current
subarray i.e. push (pivot+1) into stackFrom, push (to) into stackTo
SUBSTEP 3. go on to deal with the left half of
the current subarray i.e. to=pivot-1
}
STEP 2: if(neither of the stacks is empty)
Get a new subarray to deal with from the stacks.
i.e. start=pop(stackFrom); to=pop(stackTo);
STEP 3: both stacks are empty, and array has
been sorted. The program ends.

*/*/
void UnrecQuicksort(int q[],int low,int high)
{stack s1;<br/>stacks2;<br/> s1.push(low);<br/> s2.push(high);<br/> int tl,th,p;<br/> while(!s1.empty() && !s2.empty())<br/> {tl=s1.top();th=s2.top();<br/> s1.pop();s2.pop();<br/> if(tl>=th) continue;<br/> p=partition(q,tl,th);<br/> s1.push(tl);s1.push(p+1);<br/> s2.push(p-1);s2.push(th);<br/> }
}

/*非遞歸演算法2
要把遞歸演算法改寫成非遞歸演算法,可引進一個棧,這個棧的大小取決於遞歸調用的深度,最
多不會超過n,如果每次都選較大的部分進棧,處理較短的部分,遞歸深度最多不超過log2n
,也就是說快速排序需要的附加存儲開銷為O(log2n)。
*/
void UnrecQuicksort2(int q[],int low,int high)
{int *a;<襪瞎和br/> int top=0,i,j,p;<br/> a=new int[high-low+1];<br/> if(a==NULL) return;<br/> a[top++]=low;<br/>神正 a[top++]=high;<br/> while(top>0)<br/> {i=a[--top];<br/> j=a[--top];<br/> while(j {p=partition(q,j,i);<br/> if(p-j {//先分割前部,後部進棧<br/>a[top++]=p+1;<br/> a[top++]=i;<br/> i=p-1;<br/> }
else
{//先分割後部,前部進棧
a[top++]=j;
a[top++]=p-1;
j=p+1;
}
}
}
}

/*列印輸出*/
void display(int p[],int len)
{for(int i=0;i cout<}


/*測試*/
int _tmain(int argc, _TCHAR* argv[])
{int a[]={49,65,97,12,23,41,56,14};
quicksort(a,0,7);
//UnrecQuicksort(a,0,7);
//UnrecQuicksort2(a,0,7);
display(a,8);
return 0;
}

Ⅲ 程序的遞歸演算法與非遞歸的區別

1、遞歸和非遞歸(用棧) 非遞歸(用棧),也用到棧函數了,和遞歸就沒多大區別了! 每次遞歸進棧出棧,非遞歸(用棧)的每次調用棧函數也是進棧出棧。主要是在非遞歸(用棧)中,它的棧函數里比遞歸多了些賦值語句。。。所以效率上,非遞歸(用棧)比遞歸差。 只不過,遞歸越深,佔用棧空間越多。非遞歸(用棧),佔用的棧空間少。如果,遞歸的深度還沒達到超出棧空間的程度,那麼遞歸比非遞歸(用棧)好。 如果是非遞歸(不用棧),當然是非遞歸最好。 在下面的這個例子(解決「整數劃分問題」)中,說明了如果只是用棧機械的模擬,得到的結果只是: 空間不變(事實上,非遞歸應該多一些),而非遞歸的時間數倍的增加。。 感興趣的朋友運行就知道了 #include<iostream> #include<stack> #include<ctime> using namespace std; //---------------------------遞歸演算法 int q(int n,int m) { if((n<1) || (m<0)) return 0; if((n==1) ||(m==1)) return 1; if(n<m) return q(n,n); if(n==m) return q(n,m-1)+1; return q(n,m-1)+q(n-m,m); } int q(int num) { return q(num,num); } struct Point { int n,m; Point(int _n,int _m){ n=_n; m=_m;} }; //-------------------------非遞歸演算法 int _q(int n,int m) { int sum=0; Point tmp(n,m); stack<Point> s; s.push (tmp); while(!s.empty()) { tmp=s.top(); n=tmp.n; m=tmp.m; s.pop(); if((n<1) || (m<0)) ++sum; else if((n==1) ||(m==1)) ++sum; else if(n<m) s.push(Point(n,n)); else if(n==m) { ++sum; s.push(Point(n,m-1)); } else { s.push(Point(n,m-1)); s.push(Point(n-m,m)); } } return sum; } int _q(int num) { return _q(num,num); } int main() { int num; unsigned int p; do{ cout<<"Input a num:"; cin>>num; p=clock(); cout<<" 遞歸: "<<q(num)<<endl; cout<<"\t\t用時:"<<clock()-p<<endl; p=clock(); cout<<"非遞歸: "<<_q(num)<<endl; cout<<"\t\t用時:"<<clock()-p<<endl<<endl; }while(num); return 0; } 2. 如果非遞歸不是用棧做的 這里有一個網友做的漢諾塔問題的非遞歸解法 看了真讓人汗顏 這樣的規律都有人發現 下載地址是: http://wenku..com/view/cfd56b3610661ed9ad51f3f9.html 此演算法不是用大家以前熟悉的遞歸演算法 雖然沒運行 可以猜想 這個程序的空間和時間效率毫無疑問會大幅度提高。 3. 總結: 直接引用《演算法設計與分析(第二版)》里的一段話: 結構清晰,可讀性強,而且容易用數學歸納法來證明演算法的正確性,而且它為設計演算法,調試程序帶來很大方便。 然而遞歸演算法的運行效率較低,無論是耗費的計算時間還是佔用的存儲空間都比非遞歸演算法要多 僅僅是機械地模擬還不能達到減少計算時間和存儲空間的目的。因此,還需要根據具體程序和特點對遞歸調用的工作棧進行簡化,盡量減少棧的操作,壓縮棧存儲以達到節省計算時間和存儲空間的目的。

Ⅳ 非遞歸演算法比較有哪些主要的優點和缺點

非遞歸演算法和遞歸演算法的主要優缺點:

非遞歸演算法的優點:如果需要處理的數據規模比較大的時候,適合使用非遞歸演算法。缺點:程序代碼的可讀性差一些。
遞歸演算法的優點:程序代碼的可讀性要比非遞歸演算法的好,如果需要處理的數據量比較小的時候,適合使用遞歸演算法。缺點:當需要處理的數據規模比較大的時候,就不適合使用遞歸演算法了。因為遞歸演算法涉及到對堆棧的頻繁操作(入棧、出棧),系統效率會很低,嚴重的時候會導致系統崩潰。

Ⅳ 二叉樹的遍歷非遞歸演算法中應注意哪些問題

先序非遞歸演算法
【思路】
假設:T是要遍歷樹的根指針,若T != NULL
對於非遞歸演算法,引入棧模擬遞歸工作棧,初始時棧為空。
問題:如何用棧來保存信息,使得在先序遍歷過左子樹後,能利用棧頂信息獲取T的右子樹的根指針?
方法1:訪問T->data後,將T入棧,遍歷左子樹;遍歷完左子樹返回時,棧頂元素應扮談彎為T,出棧,再先序遍歷T的右子樹。
方法2:訪問T->data後,將T->rchild入棧,遍歷左子樹;遍歷完左子樹返回時,棧頂元素應為T->rchild,出棧,遍歷以該指針為根的子樹。
【演算法1】
void PreOrder(BiTree T, Status ( *Visit ) (ElemType e))

{ // 基於方法一,流程圖如右,當型循環
InitStack(S);
while ( T!=NULL || !StackEmpty(S)){
while ( T != NULL ){
Visit(T->data) ;
Push(S,T);
T = T->lchild;
}

if( !StackEmpty(S) ){
Pop(S,T);
T = T->rchild;
}
}
}
【演算法2】
void PreOrder(BiTree T, Status ( *Visit ) (ElemType e))

{ // 基於方法二,流程圖如右,當型循環
InitStack(S);

while ( T!=NULL || !StackEmpty(S) ){
while ( T != NULL ){
Visit(T->data);
Push(S, T->rchild);
T = T->lchild;
}
if ( !StackEmpty(S) ){
Pop(S,T);
}
}
}
進一步考慮:對於處理流程中的循環體的直到型、當型+直到型的實現。
中序非遞歸演算法
【思路】
T是要遍歷樹的根指針,中序遍歷要求廳悶在遍歷完左子樹後,訪問根,再遍歷右子樹。
問題:如何用棧來保存信息,使得在中序遍歷過左子樹後,能利用棧頂信息獲取T指針?
方法:先將T入棧,遍歷左子樹;遍歷完左子樹返回時,棧頂元素應為T,出棧,訪問T->data,再中序遍歷T的右子樹。

【演算法】
void InOrder(BiTree T, Status ( *Visit ) (ElemType e))
{ // 流程圖如右,當型循環
InitStack(S);

while ( T!=NULL || !StackEmpty(S) ){
while ( T != NULL ){
Push(S,T);
T = T->lchild;
}
if( !StackEmpty(S) ){
Pop(S, T);
Visit(T->data);
T = T->rchild;
}
}
}
進一步考慮:對於處理流程中的循環體的直到型、當型+直到型的實現。
後序非遞歸演算法
【思路】

T是要遍歷樹的根指針,後序遍歷要求在遍歷完左右子樹後,再訪問根。需要判斷根結點的左右子樹是否均遍歷過。
可採用標記法侍升,結點入棧時,配一個標志tag一同入棧(0:遍歷左子樹前的現場保護,1:遍歷右子樹前的現場保護)。
首先將T和tag(為0)入棧,遍歷左子樹;返回後,修改棧頂tag為1,遍歷右子樹;最後訪問根結點。
typedef struct stackElement{
Bitree data;
char tag;
}stackElemType;
【演算法】
void PostOrder(BiTree T, Status ( *Visit ) (ElemType e))
{ // 流程圖如右,當型循環
InitStack(S);
while ( T!=NULL || !StackEmpty(S) ){
while ( T != NULL ){
Push(S,T,0);
T = T->lchild;
}

while ( !StackEmpty(S) && GetTopTag(S)==1){
Pop(S, T);
Visit(T->data);
}
if ( !StackEmpty(S) ){
SetTopTag(S, 1); // 設置棧頂標記
T = GetTopPointer(S); // 取棧頂保存的指針
T = T->rchild;
}else break;
}
}

Ⅵ 後序遍歷的非遞歸演算法是什麼

對於樹的遍歷我們最常用的三種遍歷方法分別是前序遍歷、中序遍歷和後序遍歷,使用的方法是深度優先遍歷樹的每一個節點,這些遍歷方法都是使用遞歸函數來進行實現的。

在數據量大的情況下是比較低效的,原因在於系統幫助我們調用了一個棧並且做了諸如保護現場和恢復現場等復雜的操作。

才使得遍歷可以使用非常簡單的代碼來實現,所以我們可以模仿系統中調用的棧自己可以來寫一下棧,模仿其中的過程就可以完成對於三種遍歷演算法的實現,使用自定義的棧來代替系統棧可以得到效率上的提升,下面是對於後序遍歷的非遞歸演算法的實現。

簡介

從逆後序遍歷與先序遍歷的關系中我們可以知道逆後序遍歷序列為先序遍歷交換左右子樹的遍歷順序得到的。

所以我們得到了逆後序序列之後然後逆序就可以得到後序遍歷的序列了,所以需要兩個棧,第一個棧用來存儲先序遍歷交換左右子樹的遍歷的中介結果。

Ⅶ 遞歸演算法與非遞歸演算法的比較

否,一般而言非遞歸演算法更有效;但很多時候遞歸演算法容易實現,編程簡單。

Ⅷ 二叉樹中序遍歷的非遞歸演算法

推薦這篇文章,把二叉樹的前序、中序和後續的遞歸和非遞歸演算法都講了。
http://www.cppblog.com/ngaut/archive/2006/01/01/2351.html

Ⅸ n階乘的非遞歸演算法

#include <stdio.h>

int f(int n)//n的階乘
{
int res=1;
int i;
for(i=1;i<=n;i++)
res*=i;
return res;
}
int main()
{
int n=6;
int no=f(n);
printf("%d\n",no);
return 0;
}
如上n=6;6的階乘

Ⅹ 二叉樹先序遍歷遞歸演算法和非遞歸演算法本質區別

在前面一文,說過二叉樹的遞歸遍歷演算法(二叉樹先根(先序)遍歷的改進),此文主要講二叉樹的非遞歸演算法,採用棧結構
總結先根遍歷得到的非遞歸演算法思想如下:
1)入棧,主要是先頭結點入棧,然後visit此結點
2)while,循環遍歷當前結點,直至左孩子沒有結點
3)if結點的右孩子為真,轉入1)繼續遍歷,否則退出當前結點轉入父母結點遍歷轉入1)
先看符合此思想的演算法:

[cpp] view plain print?
int (const BiTree &T, int (*VisitNode)(TElemType data))
{
if (T == NULL)
{
return -1;
}

BiTNode *pBiNode = T;
SqStack S;
InitStack(&S);
Push(&S, (SElemType)T);

while (!IsStackEmpty(S))
{
while (pBiNode)
{
VisitNode(pBiNode->data);
if (pBiNode != T)
{
Push(&S, (SElemType)pBiNode);
}
pBiNode = pBiNode->lchild;
}
if(pBiNode == NULL)
{
Pop(&S, (SElemType*)&pBiNode);
}
if ( pBiNode->rchild == NULL)
{
Pop(&S, (SElemType*)&pBiNode); //如果此時棧已空,就有問題
}
pBiNode = pBiNode->rchild;
}

return 0;
}

熱點內容
創造與魔法ios腳本刷龍涎草 發布:2024-05-22 12:44:22 瀏覽:524
如何從安卓導數據到蘋果 發布:2024-05-22 12:15:59 瀏覽:274
博越互聯版屬於什麼配置 發布:2024-05-22 12:11:46 瀏覽:224
伺服器除了dns還有什麼 發布:2024-05-22 11:58:14 瀏覽:291
android開發背景 發布:2024-05-22 11:54:01 瀏覽:181
java文件怎麼保存 發布:2024-05-22 11:17:17 瀏覽:828
安卓系統是哪裡造的 發布:2024-05-22 11:11:23 瀏覽:474
linux下sh 發布:2024-05-22 11:10:16 瀏覽:310
勞動資源配置中的自然配置是什麼 發布:2024-05-22 10:54:53 瀏覽:676
asp的資料庫 發布:2024-05-22 10:29:05 瀏覽:139