如何遍历具有两个节点的链接节点

How to loop through linked nodes that have two nodes

本文关键字:节点 两个 链接 何遍历 遍历      更新时间:2023-10-16

我想遍历这个节点系统,确保命中每个节点,但我不想使用递归。每个节点实际上有两个链接节点。我不知道这是否被称为双链表还是什么。

节点看起来像

class Node {
private:
Node* next_node_type_a;
Node* next_node_type_b;
}

|next_node_type_a| -> 
|next_node_type_a|  ->  |next_node_type_b| ->
|start-node|  ->  
|next_node_type_b|  ->  |next_node_type_a| ->
|next_node_type_b| ->

最初我没有看到第二个节点,所以我有

while(node){
DoStuffWithNode(node);
node = node->GetNextNodeTypeA();
}

但是我如何修改它以遍历仍在使用 while 循环的两个节点路径?

下面是一些可以处理的示例代码

// Example program
#include <iostream>
#include <string>
class Node {
public:
Node* node_left;
Node* node_right;
std::string value;
Node();
};
Node::Node(){
node_left = 0;
node_right = 0;
}
int main()
{
Node start;
Node a;
Node b;
Node c;
Node d;
Node e;
Node f;
start.value = "start";
a.value = "a";
b.value = "b";
c.value = "c";
d.value = "d";
e.value = "e";
f.value = "f";
start.node_left = &a;
start.node_right = &b;
a.node_left = &c;
a.node_right = &d;
b.node_left = &e;
b.node_right = &f;
Node *n = &start;
while(n){
std::cout << "New node: " << n->value << std::endl;
n = n->node_left;
}
return 0;
}

编辑:我刚刚意识到这是一棵树。

递归是迭代二叉树的惯用方式,如其他答案所示,如果您需要迭代解决方案,则可以使用其他数据结构(如std::queue(迭代遍历所有节点。

这称为广度优先搜索,请务必注意,遍历的顺序将与递归的顺序不同,递归是深度优先搜索的实现。

std::queue<Node*> nodesToVisit;
nodesToVisit.push(&start);
while (nodesToVisit.size()) 
{
Node* n = nodesToVisit.front();
nodesToVisit.pop();
std::cout << "New node: " << n->value << std::endl;
if (n->node_left)
{
nodesToVisit.push(n->node_left);
}
if (n->node_right)
{
nodesToVisit.push(n->node_right);
}
}

相同的方法也适用于非二叉树,但需要额外的代码来处理循环图,例如跟踪std::set中所有访问过的节点。

最简单的解决方案是使用递归。由于(平衡(二叉树的深度是O(ln(n))因此您可以放心地假设您不会获得堆栈溢出。

void apply(Node* n)
{
if (n == nullptr) {
return;
}
DoStuffWithNode(n);
apply(n->node_left);
apply(n->node_right);
}

递归访问每个节点可以做到这一点:以下内容将导致深度优先搜索

std::vector<Node*> BuildList(Node* root) {
vector<Node*> nodes;
if(root) {
nodes.push_back(root);
BuildList(root, nodes);
}
return nodes;
}
void BuildList(Node* node, std::vector<Node*> current) {
if(node->next_node_type_a) {
current.push_back(node->next_node_type_a);
BuildList(node->next_node_type_a, current);
}
if(node->next_node_type_b) {
current.push_back(node->next_node_type_b);
BuildList(node->next_node_type_b, current);
}
}

当然,如果您的节点链接回自身,这可能会失败,因此请考虑将std::vector换成集合类型

您使用的数据结构是二叉树。要在不递归的情况下遍历二叉树,请使用广度优先方法,该方法涉及使用队列来保存每个节点并对其进行处理。

在 Node 类上添加.discovery值将阻止处理任何 Node 两次。如果要重用此函数,请在处理所有节点后重置此发现的值。仅当您无法保证任何节点指向祖先节点或指向自身时,才需要使用此值。

#include <iostream> 
#include <queue> 
using namespace std;
void BreadthFirst(Node start) {
Queue<Node> Q;
start.discovered = true;
Q.push(start)
while (!Q.isEmpty()) {
Node n = Q.pop()
cout << n.value << endl;
if (n->next_node_type_a != null) {
if(n->next_node_type_a.discovered == false) {
n->next_node_type_a.discovered = true;
Q.push(n->next_node_type_a);
}
}
if (n->next_node_type_b != null) {
if(n->next_node_type_b.discovered == false) {
n->next_node_type_b.discovered = true;
Q.push(n->next_node_type_b);
}
}
}
}