二叉树的遍历

二叉树的遍历方式:前序、中序、后序、层次 以及 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 );
}



你可能感兴趣的:(二叉树的遍历)