zoukankan      html  css  js  c++  java
  • 二叉树的遍历

    二叉树的遍历方式:前序、中序、后序、层次 以及 morris遍历。
    morris遍历二叉树,将当前遍历到达的节点记为 cur.
    	cur没有左孩子:
    		cur 向右孩子移动.
    	cur有左孩子:
    		找到cur的左子树的最右节点记为 rightmost.
    		rightmost的右孩子指针指向NULL, 让其指向cur, 然后cur向左孩子移动.
    		rightmost的右孩子指针指向cur, 让其指向空, 然后cur向右孩子移动.
    




    前序遍历:递归实现
    void preorderRecursionTraversal( NodeBinaryTree *root ) {
    	if( root == NULL ) {
    		return;
    	}
    	printf( "%d, ", root->val );
    	preorderRecursionTraversal( root->left, a, aSize );
    	preorderRecursionTraversal( root->right, a, aSize );
    }
    
    前序遍历:迭代实现
    #define NEW_STACK( s, capacity ) ({                             
    	*s = malloc( sizeof(**s) + sizeof((*s)->a[0]) * capacity ); 
    	*s->t = 0; (*s)->c = capacity;                              
    })
    #define PUSH_STACK( s, d ) ({ s->a[s->t++] = d; })
    #define POP_STACK( s, d ) ({ *d = s->a[--s->t]; })
    #define EMPTY_STACK( s ) (s->t < 1)
    #define FULL_STACK( s ) (s->t >= s->c)
    #define DEL_STACK( s ) ({ if( s != NULL && *s != NULL ) { free( *s ); *s = NULL; } })
    
    typedef struct Stack {
    	int c;
    	int t;
    	void *a[0];
    } Stack;
    
    void preorderIterativeTraversal( NodeBinaryTree *root ) {
    	Stack *s = NULL;
    
    	if( root != NULL ) {
    		NEW_STACK( &s, 10000 );
    		PUSH_STACK( s, root );
    	}
    	while( !EMPTY_STACK( s ) ) {
    		POP_STACK( s, &root );
    		printf( "%d, ", root->val );
    		if( root->right != NULL ) {
    			PUSH_STACK( s, root->right );
    		}
    		if( root->left != NULL ) {
    			PUSH_STACK( s, root->left );
    		}
    	}
    	DEL_STACK( &s );
    }
    
    前序遍历:morris实现
    只处理第一次到达的节点.
    
    void preorderMorrisTraversal( NodeBinaryTree *root ) {
    	while( root != NULL ) {
    		if( root->left != NULL ) {
    			NodeBinaryTree *rightmost = root->left;
    			while( rightmost->right != NULL && rightmost->right != root ) {
    				// cur节点的左子树的最右节点.
    				rightmost = rightmost->right;
    			}
    			if( rightmost->right != NULL ) {
    				rightmost->right = NULL;
    				root = root->right;
    			} else {
    				// cur节点的左子树的最右节点没有被修改过,说明是第一次到达cur节点.
    				printf( "%d, ", root->val );
    				rightmost->right = root;
    				root = root->left;
    			}
    		} else {
    			// cur节点没有子树.
    			printf( "%d, ", root->val );
    			root = root->right;
    		}
    	}
    }
    

    中序遍历:递归实现
    void inorderRecursionTraversal( NodeBinaryTree *root ) {
    	if( root == NULL ) {
    		return;
    	}
    	inorderRecursionTraversal( root->left );
    	printf( "%d, ", root->val );
    	inorderRecursionTraversal( root->right );
    }
    
    中序遍历:迭代实现
    #define NEW_STACK( s, capacity ) ({                             
    	*s = malloc( sizeof(**s) + sizeof((*s)->a[0]) * capacity ); 
    	*s->c = capacity;                                           
    	*s->t = 0;                                                  
    })
    #define PUSH_STACK( s, d )  ({ s->a[s->t++] = d; })
    #define POP_STACK( s, d )   ({ *d = s->a[--s->t]; })
    #define PEEK_STACK( s, d )  ({ *d = s->a[s->t - 1]; })
    #define SIZE_STACK( s )     (s->t)
    #define EMPTY_STACK( s )    (s->t < 1)
    #define FULL_STACK( s )     (s->t >= s->c)
    #define CLEAR_STACK( s )    ({ s->t = 0; })
    #define DEL_STACK( s )      ({ if( s != NULL && *s != NULL ) { free( *s ); *s = NULL; } })
    
    typedef struct Stack {
    	int c;
    	int t;
    	void *a[0];
    } Stack;
    
    void inorderIterativeTraversal( NodeBinaryTree *root ) {
    	Stack *s = NULL;
    
    	NEW_STACK( &s, 10000 );
    	#if 0
    	while( root != NULL || !EMPTY_STACK( s ) ) {
    		if( root != NULL ) {
    			PUSH_STACK( s, root );
    			root = root->left;
    		} else {
    			POP_STACK( s, &root );
    			printf( "%d, ", root->val );
    			root = root->right;
    		}
    	}
    	#else
    	while( root != NULL || !EMPTY_STACK( s ) ) {
    		while( root != NULL ) {
    			PUSH_STACK( s, root );
    			root = root->left;
    		}
    		POP_STACK( s, &root );
    		printf( "%d, ", root->val );
    		root = root->right;
    	}
    	#endif
    	DEL_STACK( &s );
    }
    
    中序遍历:morris实现
    只处理没有左子树的节点和第2次到达的节点.
    
    void inorderMorrisTraversal( NodeBinaryTree *root ) {
    	while( root != NULL ) {
    		if( root->left != NULL ) {
    			NodeBinaryTree *rightmost = root->left;
    			while( rightmost->right != NULL && rightmost->right != root ) {
    				// cur节点的左子树的最右节点.
    				rightmost = rightmost->right;
    			}
    			if( rightmost->right != NULL ) {
    				// cur节点的左子最右节点被修改过,说明是第2次到达cur节点,
    				// 即cur节点的左子树已经处理完毕.
    				printf( "%d, ", root->val );
    				rightmost->right = NULL;
    				root = root->right;
    			} else {
    				rightmost->right = root;
    				root = root->left;
    			}
    		} else {
    			// cur节点没有左子树.
    			printf( "%d, ", root->val );
    			root = root->right;
    		}
    	}
    }
    

    后序遍历:递归实现
    void postorderRecursionTraversal( NodeBinaryTree *root ) {
    	if( root == NULL ) {
    		return;
    	}
    	postorderRecursionTraversal( root->left );
    	postorderRecursionTraversal( root->right );
    	printf( "%d, ", root->val );
    }
    
    后序遍历:迭代实现
    #define NEW_STACK( s, capacity ) ({                             
    	*s = malloc( sizeof(**s) + sizeof((*s)->a[0]) * capacity ); 
    	*s->c = capacity;                                           
    	*s->t = 0;                                                  
    })
    #define PUSH_STACK( s, d )  ({ s->a[s->t++] = d; })
    #define POP_STACK( s, d )   ({ *d = s->a[--s->t]; })
    #define PEEK_STACK( s, d )  ({ *d = s->a[s->t - 1]; })
    #define SIZE_STACK( s )     (s->t)
    #define EMPTY_STACK( s )    (s->t < 1)
    #define FULL_STACK( s )     (s->t >= s->c)
    #define CLEAR_STACK( s )    ({ s->t = 0; })
    #define DEL_STACK( s )      ({ if( s != NULL && *s != NULL ) { free( *s ); *s = NULL; } })
    
    typedef struct Stack {
    	int c;
    	int t;
    	void *a[0];
    } Stack;
    
    // 另外一种实现:利用两个栈, 将 中左右遍历 改为 中右左遍历, 中右左过程使用栈1, 左右中过程使用栈2.
    // 将 中右左过程中元素输出的地方 改为 输出元素压入栈2,
    // 最后将栈2所有元素弹栈并输出, 得到左右中遍历序列, 即后序遍历.
    void postorderIterativeTraversal( NodeBinaryTree *root ) {
    	NodeBinaryTree *lasttime = root;
    	Stack *s = NULL;
    
    	NEW_STACK( &s, 10000 );
    	if( root != NULL ) {
    		PUSH_STACK( s, root );
    	}
    	while( !EMPTY_STACK( s ) ) {
    		PEEK_STACK( s, &root );
    		if( root->left != NULL && root->left != lasttime && root->right != lasttime ) {
    			PUSH_STACK( s, root->left );
    		} else if( root->right != NULL && root->right != lasttime ) {
    			PUSH_STACK( s, root->right );
    		} else {
    			POP_STACK( s, &lasttime );
    			printf( "%d, ", lasttime->val );
    		}
    	}
    	DEL_STACK( &s );
    }
    
    后序遍历:morris实现
    最先逆序处理第2次到达的节点的左子树的右边界节点,
    最后逆序处理整棵树的右边界节点.
    
    static void reverseHandleRightBoundary( NodeBinaryTree *root ) {
    	NodeBinaryTree *p1 = NULL, *p2 = NULL, *p3 = NULL;
    
    	for( p2 = root, p1 = NULL; p2 != NULL; p2 = p3 ) {
    		p3 = p2->right;
    		p2->right = p1;
    		p1 = p2;
    	}
    	for( p2 = p1, p1 = NULL; p2 != NULL; p2 = p3 ) {
    		printf( "%d, ", p2->val );
    		p3 = p2->right;
    		p2->right = p1;
    		p1 = p2;
    	}
    }
    
    void postorderMorrisTraversal( NodeBinaryTree *root ) {
    	NodeBinaryTree *cur = root;
    
    	while( cur != NULL ) {
    		if( cur->left != NULL ) {
    			NodeBinaryTree *rightmost = cur->left;
    			while( rightmost->right != NULL && rightmost->right != cur ) {
    				rightmost = rightmost->right;
    			}
    			if( rightmost->right != NULL ) {
    				// cur节点的左子最右节点被修改过, 说明是第二次来到cur节点.
    				rightmost->right = NULL;
    				// 逆序处理cur节点的左子树的右边界节点.
    				reverseHandleRightBoundary( cur->left );
    				cur = cur->right;
    			} else {
    				rightmost->right = cur;
    				cur = cur->left;
    			}
    		} else {
    			cur = cur->right;
    		}
    	}
    	// 最后逆序处理整棵树的右边界节点.
    	reverseHandleRightBoundary( root );
    }
    

    层次遍历:迭代实现
    #define NEW_QUEUE( q, capacity ) ({                             
    	*q = malloc( sizeof(**q) + sizeof((*q)->a[0]) * capacity ); 
    	*q->c = capacity;                                           
    	*q->s = 0;                                                  
    	*q->h = 0;                                                  
    })
    #define ADD_QUEUE( q, d )   ({ q->a[(q->h + q->s++) % q->c] = d; })
    #define POLL_QUEUE( q, d )  ({ *d = q->a[q->h]; q->h = (q->h + 1) % q->c; --q->s; })
    #define PEEK_QUEUE( q, d )  ({ *d = q->a[q->h]; })
    #define SIZE_QUEUE( q )     (q->s)
    #define EMPTY_QUEUE( q )    (q->s < 1)
    #define FULL_QUEUE( q )     (q->s >= q->c)
    #define CLEAR_QUEUE( q )    ({ q->h = q->s = 0; })
    #define DEL_QUEUE( q )      ({ if( q != NULL && *q != NULL ) { free( *q ); *q = NULL; } })
    
    typedef struct Queue {
    	int32_t c;
    	int32_t s;
    	int32_t h;
    	void *a[0];
    } Queue;
    
    void levelOrderTraversal( NodeBinaryTree *root ) {
    	Queue *q = NULL;
    
    	NEW_QUEUE( &q, 10000 );
    	if( root != NULL ) {
    		ADD_QUEUE( q, root );
    	}
    	while( !EMPTY_QUEUE( q ) ) {
    		int32_t count = SIZE_QUEUE( q );
    		while( --count >= 0 ) {
    			POLL_QUEUE( q, &root );
    			printf( "%d, ", root->val );
    			if( root->left != NULL ) {
    				ADD_QUEUE( q, root->left );
    			}
    			if( root->right != NULL ) {
    				ADD_QUEUE( q, root->right );
    			}
    		}
    	}
    
    	DEL_QUEUE( &q );
    }
    



  • 相关阅读:
    shell编程之 ()[] {}
    mysql环境搭建
    CSS布局基础——BFC
    Java线程
    chrome developer tool—— 断点调试篇
    JavaScript技巧[转载]
    如何在github中创建演示demo
    rem在响应式布局中的应用
    javascript模块化
    浏览器客户端的数据存储
  • 原文地址:https://www.cnblogs.com/hujunxiang98/p/13029440.html
Copyright © 2011-2022 走看看