1 树的广度优先遍历算法
广度优先遍历算法,又叫宽度优先遍历,或横向优先遍历,是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。
如上图所示的二叉树,A 是第一个访问的,然后顺序是 B、C,然后再是 D、E、F、G。
那么,怎样才能来保证这个访问的顺序呢?
借助队列数据结构,由于队列是先进先出的顺序,因此可以先将左子树入队,然后再将右子树入队。
这样一来,左子树结点就存在队头,可以先被访问到。
//广度优先遍历
java版本:
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Main2{
public ArrayList<Integer> BfsTree(TreeNode root) {
ArrayList<Integer> lists = new ArrayList<>();
if(root == null)
return lists;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode tree = queue.poll();
if(tree.left != null)
queue.offer(tree.left);
if(tree.right != null)
queue.offer(tree.right);
lists.add(tree.val);
}
return lists;
}
}
c++版本
void breadthFirstTravel(Node* root){
queue<Node *> nodeQueue; //使用C++的STL标准模板库
nodeQueue.push(root);
Node *node;
while(!nodeQueue.empty()){
node = nodeQueue.front();
nodeQueue.pop();
printf(format, node->data);
if(node->lchild){
nodeQueue.push(node->lchild); //先将左子树入队
}
if(node->rchild){
nodeQueue.push(node->rchild); //再将右子树入队
}
}
}
1.3 左右交替的层序遍历(使用双端队列)
c++版本
方法1 使用双端队列
void Z_LeveOrder_duque(struct BtNode* p)
{
if (NULL == p) return;
std::deque<struct BtNode*> deq;
deq.push_front(p);
deq.push_back(NULL); // 标志位,划分不同层
while (!deq.empty())
{
struct BtNode* pCur = NULL;
if (deq.front() == deq.back()) break; // 队头 == 队尾 == NULL ,所有元素已经遍历完
if(deq.back() == NULL)
{
while (deq.front() != NULL)
{
pCur = deq.front();
deq.pop_front();
std::cout << pCur->data << " ";
if (pCur->leftchild != NULL)
{
deq.push_back(pCur->leftchild);
}
if (pCur->rightchild != NULL)
{
deq.push_back(pCur->rightchild);
}
}
}
if (deq.front() == NULL)
{
while (deq.back() != NULL)
{
pCur = deq.back();
deq.pop_back();
std::cout << pCur->data << " ";
if (pCur->rightchild != NULL)
{
deq.push_front(pCur->rightchild); // 头删尾插
}
if (pCur->leftchild != NULL)
{
deq.push_front(pCur->leftchild);
}
}
}
}
std::cout << std::endl;
}
方法2 :使用两个栈实现
此方法与双端队列实现方法相同,这里就不再赘述。
void Z_LeveOrder_stack(struct BtNode* p)
{
if (NULL == p) return;
std::stack<struct BtNode*> st1;
std::stack<struct BtNode*> st2;
st1.push(p);
while (!st1.empty() || !st2.empty())
{
while (!st1.empty())
{
struct BtNode* pCur = st1.top();
st1.pop();
std::cout << pCur->data << " ";
if (pCur->leftchild != NULL)
{
st2.push(pCur->leftchild);
}
if (pCur->rightchild != NULL)
{
st2.push(pCur->rightchild);
}
}
while (!st2.empty())
{
struct BtNode* pCur = st2.top();
st2.pop();
std::cout << pCur->data << " ";
if (pCur->rightchild != NULL)
{
st1.push(pCur->rightchild);
}
if (pCur->leftchild != NULL)
{
st1.push(pCur->leftchild);
}
}
}
std::cout << std::endl;
}
方法3 栈与队列实现
这里需要注意的是,栈与队列实现,必须让根结点入栈,然后不论是队列或是栈都以先右孩子后左孩子的顺序存储。栈负责正向从左到右访问,队列负责反向从右向左访问。
void Z_LeveOrder_StackAndQueue(struct BtNode* p)
{
if (NULL == p) return;
std::stack<struct BtNode*> st;
std::queue<struct BtNode*> que;
st.push(p); // 入栈
while (!st.empty() || !que.empty())
{
while (!st.empty())
{
p = st.top(); st.pop();
std::cout << p->data << " ";
if (p->rightchild != NULL)
{
que.push(p->rightchild);
}
if (p->leftchild != NULL)
{
que.push(p->leftchild);
}
}
while (!que.empty())
{
p = que.front(); que.pop();
std::cout << p->data << " ";
if (p->rightchild != NULL)
{
st.push(p->rightchild);
}
if (p->leftchild != NULL)
{
st.push(p->leftchild);
}
}
}
std::cout << std::endl;
}
2 树的深度优先遍历算法
深度优先遍历算法是遍历算法的一种。是沿着树的深度遍历树的节点。
当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。
如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
如上图所示的二叉树:
A 是第一个访问的,然后顺序是 B、D,然后是 E。接着再是 C、F、G。
那么,怎么样才能来保证这个访问的顺序呢?
分析一下,在遍历了根结点后,就开始遍历左子树,最后才是右子树。
因此可以借助堆栈的数据结构,由于堆栈是后进先出的顺序,由此可以先将右子树压栈,然后再对左子树压栈,
这样一来,左子树结点就存在了栈顶上,因此某结点的左子树能在它的右子树遍历之前被遍历。
//深度优先遍历
java版本:
public void depthTraversal(ListNode node){
if(node==null){
System.out.print("empty tree");
return;
}
Stack<ListNode> stack = new Stack<ListNode>();
stack.push(node);
while(!stack.isEmpty()){
ListNode rnode = stack.pop();
System.out.print(rnode.val);
if(rnode.right!=null){
stack.push(rnode.right);
}
if(rnode.left!=null){
stack.push(rnode.left);
}
}
}
c++版本:
void depthFirstTravel(Node* root){
stack<Node *> nodeStack; //使用C++的STL标准模板库
nodeStack.push(root);
Node *node;
while(!nodeStack.empty()){
node = nodeStack.top();
printf(format, node->data); //遍历根结点
nodeStack.pop();
if(node->rchild){
nodeStack.push(node->rchild); //先将右子树压栈
}
if(node->lchild){
nodeStack.push(node->lchild); //再将左子树压栈
}
}
}