目次
1.2 ポストオーダー トラバーサル (2 つのスタックを使用)
1.3 ポストオーダー トラバーサル (スタックを使用) show 操作
二分木の構造:
class Node {
public:
Node(int v) {
value = v;
}
public:
int value;
Node* left;
Node* right;
};
1. 非再帰形式により、前中後トラバーサルを実現
1.1 予約注文トラバーサル
1.ポップアップしたらすぐに印刷する
2. 右があれば右を押す
3. 左の場合は、左を押します
void pre(Node* head) {
cout << "前序遍历:" << endl;
if (head != nullptr) {
stack<Node*> stack;
stack.push(head);
while (!stack.empty()) {
head = stack.top();
stack.pop();
cout << head->value << " ";
if (head->right != nullptr) {
stack.push(head->right);
}
if (head->left != nullptr) {
stack.push(head->left);
}
}
}
cout << endl;
}
1.2 ポストオーダー トラバーサル (2 つのスタックを使用)
頭の右左の順序 はおなじみ ですか?そうです、逆順トラバーサルじゃないですか。
1. 2 番目のスタック res にポップします。
2. 左の場合は、左を押します
3. 右があれば右を押す
4.最後に、すべてを解像度で印刷します
void pos(Node* head) {
cout << "后序遍历:" << endl;
if (head != nullptr) {
stack<Node*> st1;
stack<Node*> st2;
st1.push(head);
while (!st1.empty()) {
head = st1.top();
st1.pop();
st2.push(head);
if (head->left != nullptr) {
st1.push(head->left);
}
if (head->right != nullptr) {
st1.push(head->right);
}
}
while (!st2.empty()) {
cout << st2.top()->value << " ";
st2.pop();
}
}
cout << endl;
}
1.3 ポストオーダー トラバーサル (スタックを使用) show 操作
1 つのスタックのみを使用して完了する
void pos2(Node* h) {
cout<<"后序遍历炫技版: "<<endl;
if (h != nullptr) {
stack<Node*> stack;
stack.push(h);
Node* c = nullptr;
while (!stack.empty()) {
c = stack.top();
//说明这个c的左树都还没处理呢,肯定先要去处理左树
if (c->left != nullptr && h != c->left && h != c->right) {
stack.push(c->left);
}
//说明左树处理了,但右树没有处理,那就去处理右树
else if (c->right != nullptr && h != c->right) {
stack.push(c->right);
}
//左右树都处理完了,那就去处理头
else {
cout << stack.top()->value<<" ";
stack.pop();
h = c;//处理一个,那就让h记录刚处理的位置
}
}
}
cout << endl;
}
1.4 順序通りのトラバーサル
1.左ボーダー全体を順番にスタックにプッシュします
2.1 実行できない場合はスタックをポップし、ポップされた右の木で実行を継続する
あなたはなぜこれをやっているのですか?
void in(Node* cur) {
cout<<"中序遍历 : "<<endl;
if (cur != nullptr) {
stack<Node*> stack;
while (!stack.empty() || cur != nullptr) {
if (cur != nullptr) {
stack.push(cur);
cur = cur->left;
}
else {
cur = stack.top();
stack.pop();
cout << cur->value << " ";
cur = cur->right;
}
}
}
cout << endl;
}
2. 二分木の層ごとの走査を実現する
1.キューを使用する
ポップアップしたら印刷し、左の木に進み、右の木に入る
void level(Node* head) {
if (head == nullptr) {
return;
}
queue<Node*> queue;
queue.push(head);
while (!queue.empty()) {
Node* cur = queue.front();
cout << cur->value << " ";
queue.pop();
//System.out.println(cur.value);
if (cur->left != nullptr) {
queue.push(cur->left);
}
if (cur->right != nullptr) {
queue.push(cur->right);
}
}
}
Niuke の回答の方法を使用することもできます: ジグザグ印刷を実現する
vector<vector<int> > levelOrder(TreeNode* root) {
// write code here
vector<vector<int>> vt;
if(root==nullptr)
return vt;
//队列存储,进行层次遍历
queue<TreeNode*> q;
q.push(root);
TreeNode* cur;
while(!q.empty()){
vector<int> temp;
int n=q.size();
for(int i=0;i<n;++i){
cur=q.front();
q.pop();
temp.push_back(cur->val);
if(cur->left)
q.push(cur->left);
if(cur->right)
q.push(cur->right);
}
vt.push_back(temp);//一层都统计完之后再加入
}
return vt;
}
3. 二分木が最も多い層を数えます
各レイヤーを印刷するだけでなく、レイヤーの開始位置と終了位置を検出することもできます
1. 地図を使う
int maxWidthUseMap(Node* head) {
if (head == nullptr) {
return 0;
}
queue<Node*> queue;
queue.push(head);
// key 在 哪一层,value
unordered_map <Node*, int> levelMap;
levelMap.insert(make_pair(head,1));
int curLevel = 1; // 当前你正在统计哪一层的宽度
int curLevelNodes = 0; // 当前层curLevel层,宽度目前是多少
int Max = 0;
while (!queue.empty()) {
Node* cur = queue.front();
queue.pop();
int curNodeLevel = levelMap[cur];//当前的层数
if (cur->left != nullptr) {
levelMap.insert(make_pair(cur->left, curNodeLevel + 1));
queue.push(cur->left);
}
if (cur->right != nullptr) {
levelMap.insert(make_pair(cur->right, curNodeLevel + 1));
queue.push(cur->right);
}
if (curNodeLevel == curLevel) {
curLevelNodes++;
}
else {
Max = max(Max, curLevelNodes);
curLevel++;
curLevelNodes = 1;//刚开始的时候下一层肯定是1
}
}
Max = max(Max, curLevelNodes);
return Max;
}
2、地図なし
int maxWidthNoMap(Node* head) {
if (head == nullptr) {
return 0;
}
queue<Node*> queue;
queue.push(head);
Node* curEnd = head; // 当前层,最右节点是谁
Node* nextEnd = nullptr; // 下一层,最右节点是谁
int Max = 0;
int curLevelNodes = 0; // 当前层的节点数
while (!queue.empty()) {
Node* cur = queue.front();
queue.pop();
if (cur->left != nullptr) {
queue.push(cur->left);
nextEnd = cur->left;
}
if (cur->right != nullptr) {
queue.push(cur->right);
nextEnd = cur->right;
}
curLevelNodes++;
if (cur == curEnd) {
Max = max(Max, curLevelNodes);
curLevelNodes = 0;
curEnd = nextEnd;
}
}
return Max;
}
質問: 二分木のノードが与えられた場合、その後続ノードを返します
後続ノードは、彼が順番に通過する次のノードを参照します
1. 暴力:
最も簡単な方法は、親ノードが見つかるまで親を探し続け、次にトラバースして次のノードを見つけることです。
2. 後継者の元へ直行
インオーダトラバーサルなので、左頭右の順番に従わなければならず、
次に、ツリーに右サブツリーがある場合、その後続は直接右サブツリーの左端のサブツリーになります
右のサブツリーがない場合は、サブツリーが親の左のサブツリーになる親子関係になるまで上に進みます (右のサブツリーの場合は上に進みます)。
もちろん、最後のノードには後続ノードがないため、見つからないはずがないため、nullptr を返すだけです
コード:
Node* getSuccessorNode(Node* node) {
if (node == nullptr) {
return node;
}
if (node->right != nullptr) {
return getLeftMost(node->right);
}
else { // 无右子树
Node* parent = node->parent;
while (parent != nullptr && parent->right == node) { // 当前节点是其父亲节点右孩子
node = parent; // 那就继续向上去找
parent = node->parent;
}
return parent;
}
}
Node* getLeftMost(Node* node) {
if (node == nullptr) {
return node;
}
while (node->left != nullptr) {
node = node->left;
}
return node;
}
同様に、フロントドライブを探すのも逆です。
このツリーはまったく存在しませんが、再帰でシミュレートしました
明確に指定されたツリーは、ツリーをまったく構築せずに印刷できます