![](/img/trans.png)
[英]C++ Stem and Leaf Plot. I don't understand how to make a linked list of linked lists
[英]How can I understand linked lists?
我试图了解它们是如何工作的,但我遇到了很多困难。 是否有人愿意直观地解释它们,或者提供他们认为适合刚开始使用该主题的人的资源?
所以让我说我有这个:
struct node
{
int nodeNum;
nodes *next;
}
要创建“head”节点,我将执行以下操作: node *head = new node;
所以我的链表现在看起来像 。 分配后:
head->nodeNum = 10;
head->next = NULL;
我们有 。 现在,如果我想编写一个插入节点的函数,我可以写:
void insert(node *previousNode, int num)
{
previousNode = new node;
previousNode->nodeNum = num;
previousNode->next = NULL;
}
所以,如果我这样做,比如insert(head, 20);
我的新列表看起来像 ?
如果一切正确,我如何使用此信息从列表中搜索和/或删除节点? 遍历节点并不是非常直观,如head = head->next;
, 例如。 这是如何运作的?
您可以提供任何建议,使这个主题更容易理解将是伟大的。 感谢大家的帮助!
您的插入功能无法正常工作; 它只是创建一个新节点而不将其添加到列表中,并在函数返回时丢失它(给出内存泄漏):
head -> 10 -> NULL becomes head -> 10 -> NULL
(lost) 20 -> NULL
相反,它应该将列表的旧尾部链接到新节点,并在旧节点之后插入新节点:
void insert(node * prev, int num) {
node * new_node = new node;
new_node->nodeNum = num;
new_node->next = prev->next; // add the old tail after the new node
prev->next = new_node; // add the new node after the old node
}
insert(head, 20); // insert 20 after the head
// head -> 10 -> NULL becomes head -> 20 -> 10 -> NULL
如何使用此信息从列表中搜索和/或删除节点?
要进行迭代,您需要维护自己的指针,指向您正在查看的元素; 这head
开始,然后跟随next
指针,直到它到达结尾(即next
为null):
for (node * n = head; n; n = n->next) {
if (n->nodeNum == 20) {
std::cout << "Found node 20!\n";
break;
}
}
要从单链表中删除节点,需要一个指向其前面节点的指针,以便更新其next
指针:
void remove_next(node * prev) {
if (prev->next) {
node * next = prev->next->next; // Get the tail after the removed node
delete prev->next;
prev->next = next; // Add the tail after the remaining node
}
}
remove_next(head);
// head -> 20 -> 10 -> NULL becomes head -> 10 -> NULL
你的问题在这里:
void insert(node *previousNode, int num)
{
previousNode = new node;
previousNode->nodeNum = num;
previousNode->next = NULL;
}
insert(head, 20);
这是代码的作用: previousNode = new node;
创建一个指向节点的指针,并指定指向previousNode的指针。 PreviousNode以复制头开始,它现在指向一些新东西。 您现在可以为新节点分配值。 换句话说,插入的这种实现不会插入。
你想做的更像是:
void better_insert(node *previousNode, int num)
{
node *post_node = new node; #create a brand new pointer to a brand new node
post_node->nodeNum = num; #give it a number
post_node->next = previousNode->next; #we want previousNode to be behind new node
previousNode->next = post_node;
}
它的作用是:在创建一个新节点并用新指针指向它之后,我们给它一个数字。 接下来要弄清楚指针指向的位置......
让我们假装我们在链表中挥动一些节点。 所有小写字母都是指针,好吗?
a->next = b
现在说我们希望节点x
在a
之后,并且数字为10 ...我们称之为`better_insert(a,10)
post_node
指向一个新节点(我们的节点x),并被赋予10. cool ...
我们想要:
a->next = x
x->next = b
我们有:
a->next = b
x->next = null
函数的最后两行只是改变了东西,直到它适合账单
所以更详细......
我们有:
a->next = b
x->next = null
所以我们打电话:
post_node->next = previousNode->next; #we want previousNode to be behind new node
现在我们有:a-> next = b x-> next = b
现在我们打电话:
previousNode->next = post_node;
我们最终得到:
a->next = x
x->next = b
或者在其他'词'中:
a->next = x
a->next->next = b
您需要在代码中使用更多变量。 insert
操作修改两个节点。 需要将先前节点更改为指向新节点,并且需要创建新节点并使其指向前一节点之后的节点(可能是也可能不是NULL)。
void insert(node *previousNode, int num)
{
node *newnode = new node;
newnode->nodeNum = num;
newnode->next = previousNode->next;
previousNode->next = newnode;
}
要遍历列表,您可以跟踪“当前节点”,您可以从一个节点更改为下一个节点:
while (currentNode != 0) {
do_something_with(currentNode);
currentNode = currentNode->next;
}
当然,如果do_something_with
删除了节点,那么之后就无法从它向前迈进。 此外,要从单链接列表中删除节点,您需要一个指向该节点之前的节点的指针。 因此,在这种情况下,您的循环可能会跟踪两个节点,当前和之前,而不是一个。
您正在使用的术语让您感到困惑。 希望这个比喻不会让你更加困惑。 从本质上讲,想象链接列表就像这个可怕的门道一样,一旦你进入一个门口,它就会在你身后关闭,你只能看到那个房间里的东西或者去另一个房间。 从这个走廊的外面,你只知道入口的位置,而不是里面的东西。
所以,从链表结构的外部,你只知道入口,一些指针ll_node *head;
。 head
内部是一些数据和指向链表中下一个节点的指针。 遍历该链表非常简单,从入口到走廊, head
,一次进入一个走廊,直到找到您正在寻找的节点。
ll_node *current_location = head;
while (current_location != NULL)
{
// if we are at the node that you were hoping to reach, exit.
if (current_location->nodeNum == target_data_im_looking_for)
{
break;
}
// this isn't the node you're looking for, go to the next one.
current_location = current_location->next;
}
类似地,插入节点应该遍历到链表的末尾(直到current_location->next == NULL
)并将最后一个元素的下一个指针替换为您创建的新ll_node
的内存位置。 我不会为你实现这个,所以你有机会学习,但这里有足够的东西到达你想成为的地方。
通常,链表的节点不包含其编号。 它通常由一个Data和一个指向下一个节点的指针组成。 你也应该让你的代码免于拼写错误。
typedef Data int;
struct node
{
Data data; // some Data
node *next; // pointer to the next node
}
通常,您也不希望在指定的节点之后使用新节点,而是需要列表。 void insert(node *previousNode, int num)
签名建议您在某个指定的前一个节点之后需要新节点。
从技术上讲,您可以通过三种方式将新节点添加到列表中。 到列表的开头或结尾或中间的某个地方。 添加到开头是最快和最简单的。
void insert(Data num)
{
node* tmp = new node; //make a new node
tmp->data = num; //fill in data
tmp->next = head; //set the next element of new one to be the current head
head = tmp; //set new element as the head
}
这样,您就可以在列表前放置一个新元素。 您总是从头到尾遍历单向链表。
void print_all()
{
node* current = head; // start at head
while(current != NULL){ // while element exists
cout << current->data << ' '; //print its data
current = current->next; //move to the next one
}
}
当你有带数据框的图片和node* next
箭头时,很容易理解。
这是初学者。 您需要修改insert
函数以处理列表最初为空的特殊情况。 即head == NULL
。
另外,我强烈建议您尝试以面向对象的方式实现它。 写class List
使用struct node
class List
。
class List {
private:
node* head;
public:
List();
void insert(data);
void print_all();
}
尝试实现这些功能。 根据我的经验,当你以这种方式做事时,它有助于组织你对数据结构和容器的思考,而这更像是c ++这样做的事情。
在上面提到的列表中,您只有很少的信息,即nodeNum。 你应该保留更多的离子信息。 例如,在具有值nodeNum = 10的节点上,您应该从该节点获取一些其他信息。因此,当用户调用时
node* search(node *head,int num){
node *temp = head;//copy node reference into temp variable
while (temp != NULL){
if (temp->nodeNum == num){
return temp;
}
temp = temp->next;
}
}
您可以使用节点获取该节点中的数据
res = search(head,10);
删除
bool delete(node *head,int num){
node *temp = head;//copy node reference into template
node *prev = NULL;
bool isDelete = false;
while (temp != NULL){
if (temp->nodeNum == num){
break;
}else
prev = temp;
temp = temp->next;
}
}
if (temp != NULL){
prev-> next = temp->next;//maintain list
delete temp;
isDelete = true;
}
return isDelete;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.