朱有鹏C语言高级---4.9.6--单链表--遍历节点(6)
什么是遍历
(1)遍历就是把单链表中的各个节点挨个拿出来,就叫遍历。
(2)遍历的要点:一是不能遗漏、二是不能重复、追求效率。
如何遍历单链表
单链表的特点就是由很多个节点组成,头指针+头节点为整个链表的起始,最后一个节点的特征是它内部的pNext指针值为NULL。从起始到结尾中间由各个节点内部的pNext指针来挂接。由起始到结尾的路径有且只有一条。
遍历方法:从头指针+头节点开始,顺着链表挂接指针依次访问链表的各个节点,取出这个节点的数据,然后再往下一个节点,直到最后一个节点,结束返回。
编程实战
写一个链表遍历的函数,void bianli(struct node * pH ),下面的代码bianli()函数和bianli2()函数都可以用来遍历。
下面的代码,如果没有头结点,只能像bianli()函数这样遍历,不完美丑陋。如果有头结点,就可以想bianli2()函数这样完美遍历它。所以如果没有头结点,链表的算法不会完美。
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
//构建一个链表节点
struct node
{
int data; //有效数据
struct node *pNext; //指向下一个节点的指针
};
//作用:创建一个链表的节点
//返回:指针,指针指向我们本函数新创建的一个节点的首地址
struct node * create_node(int data)
{
struct node *p = (struct node *)malloc(sizeof(struct node));
if (NULL == p)
{
printf("malloc error.\n");
return NULL;
}
//清理申请到的堆内存
bzero(p, sizeof(struct node));
//填充节点
p->data = data;
p->pNext = NULL;//将来要指向下一个节点的首地址
//实际操作时将下一个节点malloc返回的指针复制给这个
return p;
}
//思路:由头指针向后遍历,直到走到原来的最后一个节点。原来最后一个节点里面的pNext是NULL,
//现在我们将它改成new就可以了。添加了之后新节点就变成了最后一个。
//pH:头指针,有链表的头指针才能找到链表。new是一个新的节点
//计算添加了新的节点后共有多少个节点,然后把这个数写进头结点中
void insert_tail(struct node *pH, struct node *new)
{
int cnt = 0;
//分两布来完成插入
//第一步,先找到链表中最后一个节点
struct node *p = pH;
while (NULL != p->pNext)
{
p = p->pNext;//往后走一个节点
cnt++;
}
//第二部,将新节点插入到最后一个节点尾部
p->pNext = new;
pH->data = cnt + 1;
}
//思路:
void insert_head(struct node *pH, struct node *new)
{
//第1步: 新节点的next指向原来的第一个节点
new->pNext = pH->pNext;
//第2部: 头节点的next指向新节点的地址
pH->pNext = new;
//第3步: 头节点中的计数要加1
pH->data += 1;
}
//遍历单链表,pH为指向单链表的头指针,遍历的节点数据打印出来
void bianli(struct node *pH)
{
//pH->data //头节点的数据,不是链表的常规数据,不要算进去了
//struct node *p = pH;//错误,因为头指针后面是头节点,头节点的数据域是节点个数
struct node *p = pH->pNext;//直接跨过了头节点,p直接走到第一个节点
printf("-----开始遍历-----\n");
while (NULL != p->pNext)//是不是最后一个节点
{
printf("node data: %d.\n", p->data);
p = p->pNext; //走到下一个节点,也就是循环增量
}
printf("node data: %d.\n", p->data);
printf("-----完了-----\n");
}
//遍历单链表,pH为指向单链表的头指针,遍历的节点数据打印出来
void bianli2(struct node *pH)
{
//pH->data //头节点的数据,不是链表的常规数据,不要算进去了
struct node *p = pH;//错误,因为头指针后面是头节点,头节点的数据域是节点个数
printf("-----开始遍历-----\n");
while (NULL != p->pNext)//是不是最后一个节点
{
p = p->pNext; //走到下一个节点,也就是循环增量
printf("node data: %d.\n", p->data);
}
printf("-----完了-----\n");
}
int main(void)
{
//不能指向NULL,因为尾插法时首先会判断头指针的值p->pNext
//struct node *pHeader = NULL;
//定义头指针,创建头节点。头节点的数据域传的是节点的个数
struct node *pHeader = create_node(0);//数据定义0表示没放数据
insert_head(pHeader, create_node(11));
insert_head(pHeader, create_node(12));
insert_head(pHeader, create_node(13));
/*
pHeader = create_node(1);
//将本节点和它前面的头指针关联起来
pHeader->pNext = create_node(2);
//将本节点和它前面的头指针关联起来
pHeader->pNext->pNext = create_node(3);
//将来要指向下一个节点的首地址
//至此创建了一个有1个头指针+3个完整节点的链表
*/
//下面是4.9.3节的代码
//访问链表的各个节点的有效数据,这个访问必须注意不能使用p,p1,p2,而只能使用pHeader
//访问链表头结点的有效数据
printf("header node data: %d.\n", pHeader->data);//pHeader->data等同于p->data
bianli2(pHeader);
/*
//访问链表第1个节点的有效数据
printf("node1 data: %d.\n", pHeader->pNext->data);
//访问链表第2个节点的有效数据
printf("node2 data: %d.\n", pHeader->pNext->pNext->data);
//访问链表第3个节点的有效数据
printf("node3 data: %d.\n", pHeader->pNext->pNext->pNext->data);
return 0;
*/
}