非遞歸DFS遍歷


  • 深度優先搜索DFS

  DFS就是回溯法,用遞歸的方法是很自然的。那么該如何遞歸呢?

  簡單的說就是:1、如果當前節點沒有被搜索過,那么處理當前節點,並標記為搜索過;如果當前節點已經被搜索過,退出;

        2、遞歸遍歷所有沒有被搜索過的臨接節點。

  注意,第一步的退出條件。遞歸必須有退出條件,否則會出現死循環。

  對任意節點調用上述DFS函數,將搜索到所有和該節點聯通的節點。

 

  • 非遞歸方式實現DFS

  遞歸和棧總是聯系在一起的,如果不采用遞歸,那么就需要自己維護一個棧。

  1、從某節點開始,入棧;

  2、當棧不為空時,循環3、4;當棧為空時,退出循環;

  3、對棧頂節點處理,標記為搜索過;注意,如果該節點的某個臨接節點處理完后,會回溯到該節點,注意不要重復處理該節點。

  4、對棧頂節點,任意找一個沒有搜索過的臨接節點,入棧(注意只入棧一個臨接節點,DFS就是找到一條路一直走下去,走不通了再回溯);如果發現該棧頂節點所有的臨接節點都被搜索過,或者該節點沒有臨接節點,將該棧頂節點出棧。 

 

  • 實現代碼

  下面是DFS的遞歸和非遞歸的代碼,C實現。為了簡單起見,搜索對象為下圖所示的滿二叉樹,用數組表示。

  

  

  1 #include<stdio.h>
  2 #include<string.h>
  3 
  4 #define true 1
  5 #define false 0
  6 #define ok 0
  7 #define error -1
  8 
  9 #define MAX_LEN  20
 10 #define TREE_LEN  10
 11 
 12 typedef struct
 13 {
 14     int arr[MAX_LEN];
 15     int top;
 16 }STACK;
 17 
 18 int is_empty(STACK *s)
 19 {
 20     if(s == NULL )
 21     {
 22         printf("null param.\n");
 23         return error;
 24     }        
 25     if(0 == s->top)
 26         return true;
 27     else
 28         return false;
 29 }
 30 
 31 int is_full(STACK *s)
 32 {
 33     if(s == NULL )
 34     {
 35         printf("null param.\n");
 36         return error;
 37     }        
 38     if( MAX_LEN == s->top)
 39         return true;
 40     else 
 41         return false;
 42 }
 43 void push(STACK* s,int elem)
 44 {
 45     if(s == NULL )
 46     {
 47         printf("null param.\n");
 48         return;
 49     }
 50         
 51     if(is_full(s))
 52     {
 53         printf("is full.\n");
 54         return;
 55     }
 56 
 57     s->arr[s->top++] = elem;
 58 }
 59 
 60 void pop(STACK* s)
 61 {
 62     if(s == NULL )
 63     {
 64         printf("null param.\n");
 65         return;
 66     }
 67         
 68     if(is_empty(s))
 69     {
 70         printf("is empty.\n");
 71         return;
 72     }    
 73 
 74     s->arr[--s->top] = 0;
 75 }
 76 
 77 int top(STACK* s)
 78 {
 79     if(s == NULL )
 80     {
 81         printf("null param.\n");
 82         return error;
 83     }
 84         
 85     if(is_empty(s))
 86     {
 87         printf("is full.\n");
 88         return error;
 89     }        
 90 
 91     return s->arr[s->top-1];
 92 }
 93 
 94 void dfs(STACK* p_stack,int *p_tree,int tree_len)
 95 {
 96     int visited[tree_len];
 97     int temp = 0;
 98     int treeIndex = 0;
 99 
100     memset(visited,0,sizeof(visited));
101     
102     push(p_stack,p_tree[treeIndex]);
103     while(!is_empty(p_stack))
104     {
105         temp = top(p_stack);
106 
107         if(treeIndex < tree_len && !visited[treeIndex])
108         {
109             printf("%d->",temp);
110             visited[treeIndex] = true;            
111         }
112 
113         if(2*treeIndex+1 < tree_len && !visited[2*treeIndex+1])
114         {
115             push(p_stack,p_tree[2*treeIndex+1]);    
116             treeIndex = 2*treeIndex+1;
117         }
118         else if( 2*treeIndex+2 < tree_len && !visited[2*treeIndex+2] )
119         {
120             push(p_stack,p_tree[2*treeIndex+2]);
121             treeIndex = 2*treeIndex+2;
122         }
123         else
124         {
125             pop(p_stack);
126             treeIndex = (treeIndex-1)>>1;
127         }        
128     }
129     printf("\n");
130 }
131 
132 
133 void dfs_reverse(int *p_tree,int*p_visited,int tree_len,int treeIndex)
134 {
135     int left,right = 0;
136 
137     if(treeIndex < tree_len && !p_visited[treeIndex])
138     {
139         printf("%d->",p_tree[treeIndex]);
140         p_visited[treeIndex] = true;
141 
142         left = 2*treeIndex+1;
143         if( left < tree_len && !p_visited[left])
144             dfs_reverse(p_tree,p_visited,tree_len,left);
145 
146         right = 2*treeIndex+2;
147         if( right < tree_len && !p_visited[right])
148             dfs_reverse(p_tree,p_visited,tree_len,right);
149     }
150 }
151 
152 
153 int tree[TREE_LEN] = {1,2,3,4,5,6,7,8,9,10};
154 STACK stack ;
155 
156 #ifdef REVERSE
157 int main()
158 {
159     int visited[TREE_LEN] = {0};
160     memset(visited,0,sizeof(visited));
161 
162     dfs_reverse(tree,visited,TREE_LEN,0);
163 }
164 #else
165 int main()
166 {
167     memset(&stack,0,sizeof(stack));
168     dfs(&stack,tree,TREE_LEN);
169 }
170 #endif

  編譯運行結果:

  可以看出結果是符合預期的。代碼中對左右子樹的處理,是對臨接節點處理的一種特殊情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM