C++ Linked list: Traversing a Linked list(遍历链表)

遍历链表很重要。  因为一旦可以遍历一个链表了, 我们就可以很容易的实现operations like print the data of the linkedc list,  或者将一个节点插入到某个特殊的位置处。

或者删除某个特定的节点, 修改节点的数据等等。

 

由于链表的第一个节点是由指针head指向。 所以我们可以存取第一个链表节点的数据, 语句为:

head -> Data;

上面的语句实际上做的事解参考我们的指针, 然后取出指针对应节点的数据:

即等价于:

(*head).Data; // using dot operator

不过一般采用的存取方式是head -> Data, 因为写法上比较简单。

当要存取第二个节点的Data 的时候, 我们当然可以用语句: head -> next  -> Data;

我们可以采用访问第三个节点数据, 第四个,。。。

然后当访问第n 个节点的数据的时候呀, 我们会想想最后head 之后跟着多长的链了, complex, messy。

所以这个方法不可取。

 

如果采用如下的方法是:

如上图, 500, 700 为节点的内存地址。 linked list 的节点的位置地址是不连续的, 后面的节点的内存地址可能在前者节点的前面。

如果我们采用迭代语句:

head = head -> next;

我们当然不需要链接那么的多的链去访问后面的节点数据, 我们采用了head 指针, 沿着链表向后面运动。

然而这个方法是有问题的。 因为我们如果这样移动head 指针的位置, 就会丢失掉head之前的节点无法存取, 而且产生了无法访问的没存垃圾。

 

所以我们的解决办法是, 定义一个遍历指针tp,  最开始tp初始化为head的内容, 也就是说tp 最开始执行第一个节点。 保持head不变, 这样我们就能够保证链表不会丢失了。

 tp = tp -> next;

 

这样我们就可以去遍历我们的指针了。 然而由于是循环语句, 我们还必须知道loop何时停止。 由于最后一个节点的next指针的内容为null, 所以这就是我们终止遍历的条件。

每次遍历的时候都要检查当前的node 是否能是最后的一个节点。

语句是:

while(tp != 0) {

//some node operation

tp = tp -> next; // update our traversing pointer to next node

}

 

下面实现。 (下面是工程中改动的文件, 要查看整个工程的文件, 参看上一个linked list 的学习笔记) 打开工程NewlinkedList中的ContactList.h, 添加printList()函数如下, 变为:

/*
 *ContactList.h
 *
 *   created on Jul 6, 2014
 *      Author: ***
 *
 *
 */

 #ifndef CONTACT_LIST_H
 #define CONTACT_LIST_H


 #include "Contact.h" // the first thing to do is to include the node header file

 class ContactList {
     public:
        ContactList(); // prototype for constructor
        void AddToHead(const std::string&);//reference, 避免复制, 更快, const, 所以不让修改
         void printList();

     private:
        Contact* head;
        int length;
};

 #endif /*end of CONTACT_LIST_H*/


 

 

打开文件ContactList.cpp, 实现上面添加的接口函数:

// an implementation of ContactList.h

#include "ContactList.h"
using namespace std;

ContactList::ContactList():head(0), length(0) {

}

void ContactList::AddToHead(const string& name) {
   Contact* newOne = new Contact(name);
   if(head == 0) {
      head = newOne;
   }
   else {
      newOne -> next = head;
      head = newOne;
   }
   length++;
}

void ContactList::printList() {
   Contact* tp;
   
   tp = head;
   
   while(tp != NULL) {
      cout << tp -> name << endl;
      
      tp = tp -> next;
   }
}


下面到NewContactListApp 做如下修改一验证遍历效果:

#include "ContactList.h"
using namespace std;

int main() {
   ContactList* cl1 = new ContactList;
   string name;
   while(true) {
      cout << "Enter the name of the contact, or q to quit:";
      cin >> name;
      if(name == "q")
         break;
      cl1->AddToHead(name);
   }

   cl1 -> printList();
   return 0;
}


编译运行如下:

 

可以看出输出的顺序和我们输入的顺序是相反的, 这是正确的。 因为我们是Build the list backward。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值