二叉树
二叉树
1. 用数组表示完全二叉树
i:下标位置, n:长度-1
2 * i + 1 ≤ n 左结点
2 * i + 2 ≤ n 右结点
2. 二叉树的遍历
深度遍历和广度遍历
深度遍历:
前序、中序、后序
递归:
迭代:
非递归——前序遍历:
根——左——右
处理完根节点后, 我们还需要保存根节点来找到右子树
使用栈来保存每一棵子树的根
void VLR_() // 非递归前序遍历 { if (rbt == nullptr) return ; stack<Node *> s; root pRoot = rbt; // 根节点 while (1) { if (pRoot != nullptr) { cout << pRoot->value << endl; s.push(pRoot); pRoot = pRoot->pLChild; } else { if (s.size() == 0) break; pRoot = s.top()->pRChild; s.pop(); } } }
非递归——中序遍历:
左——根——右
将当前节点入栈
将当前结点变为左结点操作
当前结点为空, 出栈, 打印, 将当前结点变为右结点操作
void LDR_() // 非递归中序遍历 { if (rbt == nullptr) return; stack<Node *> s; root pRoot = rbt; // 根节点 while (1) { if (pRoot) { s.push(pRoot); pRoot = pRoot->pLChild; } else { if (s.size() == 0) break; pRoot = s.top(); s.pop(); cout << pRoot->value << endl; pRoot = pRoot->pRChild; } } }
非递归——后序遍历:
左——右——根
和前序中序基本相同
区别在于如何判断从栈顶的一个结点的右结点是否被处理过
可以添加一个指针, 指向上一次弹出的结点, 如果这个结点和栈顶的右结点相同, 则代表右结点处理过了。
void LRD_() // 非递归后序遍历 { if (rbt == nullptr) return ; stack<Node *> s; Node *pRoot = rbt; Node *pLast = NULL; while (1) { if (pRoot != nullptr) { s.push(pRoot); pRoot = pRoot->pLChild; } else { if (s.size() == 0) break; pRoot = s.top(); if (pRoot->pRChild != nullptr) { if (pLast != pRoot->pRChild) { pRoot = pRoot->pRChild; } else { if (s.size() == 0) break; s.pop(); pLast = pRoot; cout << pRoot->value << endl; pRoot = nullptr; } } else { if (s.size() == 0) break; s.pop(); pLast = pRoot; cout << pRoot->value << endl; pRoot = nullptr; } } } }
广度遍历:
使用队列
将根结点添加到队列中
while (栈非空)
{
取出结点
将结点的左结点放入栈中
将结点的右结点放入栈中
}
题:将每层的结点打印在一层上:
方法1:
每次取出标记结点时, 再次将标记结点放入队列
将根节点放入队列中
将NULL作为换行标志放入队列中
while (队列非空)
{
取出结点
if (是空结点)
if (队列为空)
break;
将空结点再次进入队列
打印换行
continue
将结点的左结点放入栈中
将结点的右结点放入栈中
}
方法2:
使用两个指针标记当前行的末尾和下一行的末尾
当前行标记根
每入队一个, 下一行末尾更新一次
如果当前行的最后一个出队了, 代表下一行已经全部入队
此时输出换行符, 将下一行赋值给当前行再次处理即可
void Sequence_Traversal() // 两个指针, 进行层序遍历, 每一层在一行 { if (rbt == NULL) return ; queue<Node *> q; // 用于广度遍历 Node *pCurrent = nullptr; Node *pNext = nullptr; q.push(rbt); pCurrent = rbt; while (q.size()) { Node *pNode = q.front(); q.pop(); cout << pNode->value << ' '; if (pNode->pLChild != NULL) { q.push(pNode->pLChild); pNext = pNode->pLChild; } if (pNode->pRChild != NULL) { q.push(pNode->pRChild); pNext = pNode->pRChild; } if (pCurrent == pNode) { pCurrent = pNext; cout << endl; } } }
方法3:
使用两个队列
将当前行放入一个队列中
下一行放入另外一个队列中
如果当前行空了, 换行
交换当前行的队列和下一行的队列处理
方法4:
两个队列
根入队, 另外一个队列入队1
两个队列同时出队
将当前出队的结点的子结点入队, 子结点一定在下一层, 所以入队当前结点层数+1
如果当前出队的层数和上一个不相同, 输出换行

浙公网安备 33010602011771号