c语言listtraverse

99ANYc3cd6
预计阅读时长 18 分钟
位置: 首页 C语言 正文

ListTraverse 是数据结构中一个非常基础且重要的操作,它指的是按照一定的顺序,访问链表(或列表)中的每一个节点,并对每个节点执行指定的操作(例如打印数据、查找、修改等)。

由于 C 语言本身没有内置的链表数据类型,ListTraverse 通常是我们自己实现的链表结构的一部分。

下面我将从以下几个方面进行讲解:

  1. 核心思想
  2. 实现步骤
  3. 完整代码示例
  4. 进阶:使用函数指针

核心思想

链表是由一个个节点通过指针连接而成的,每个节点通常包含两部分:

  • 数据域:存储实际的数据。
  • 指针域:指向下一个节点的地址。

ListTraverse 的核心思想就是 从头节点开始,顺着每个节点的 next 指针一路走下去,直到最后一个节点(其 next 指针为 NULL

整个过程就像一条火车,火车头是 head,每一节车厢是一个节点,车厢之间的连接是 next 指针,终点站是 NULL


实现步骤

实现 ListTraverse 非常简单,主要分为以下几步:

  1. 获取链表的头节点指针:这是遍历的起点。
  2. 定义一个“游标”指针:通常命名为 currentp,并将其初始化为头节点指针。
  3. 进入循环:使用一个 while 循环,只要游标指针 current 不为 NULL,就继续循环。
  4. 访问节点:在循环内部,对当前游标指针 current 所指向的节点进行操作(打印其数据)。
  5. 移动游标:操作完成后,将游标指针 current 更新为 current->next,即指向下一个节点。
  6. 循环结束:当 current 变为 NULL 时,说明已经遍历到链表的末尾,循环结束。

完整代码示例

下面是一个完整的、可运行的 C 语言示例,它定义了一个简单的链表,并实现了 ListTraverse 函数来打印链表中的所有数据。

1 定义节点和链表结构

#include <stdio.h>
#include <stdlib.h>
// 1. 定义链表节点结构体
typedef struct Node {
    int data;           // 数据域,这里用 int 类型
    struct Node *next;  // 指针域,指向下一个节点
} Node;
// 为了方便,我们定义一个链表结构体,包含头指针和长度
typedef struct {
    Node *head;
    int length;
} LinkedList;

2 辅助函数(创建和初始化)

// 创建一个新节点
Node* createNode(int value) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL) {
        printf("内存分配失败!\n");
        exit(1);
    }
    newNode->data = value;
    newNode->next = NULL;
    return newNode;
}
// 初始化链表
void initList(LinkedList *list) {
    list->head = NULL;
    list->length = 0;
}

3 核心函数:ListTraverse

这是本次讲解的重点。

/**
 * @brief 遍历链表并打印每个节点的数据
 * @param list 要遍历的链表
 */
void ListTraverse(LinkedList *list) {
    // 1. 定义游标指针,并初始化为头节点
    Node *current = list->head;
    printf("开始遍历链表: ");
    // 2. 循环条件:只要 current 不为 NULL
    while (current != NULL) {
        // 3. 访问当前节点(例如打印数据)
        printf("%d -> ", current->data);
        // 4. 移动游标到下一个节点
        current = current->next;
    }
    printf("NULL\n"); // 打印链表结束的标志
}

4 其他辅助函数(添加节点)

为了演示 ListTraverse,我们需要一个往链表里添加数据的方法。

// 在链表头部添加节点(头插法)
void insertAtHead(LinkedList *list, int value) {
    Node *newNode = createNode(value);
    newNode->next = list->head; // 新节点的 next 指向原来的头节点
    list->head = newNode;      // 更新头节点为新节点
    list->length++;
}

5 main 函数(测试)

int main() {
    // 创建并初始化一个链表
    LinkedList myList;
    initList(&myList);
    // 向链表中添加一些数据
    insertAtHead(&myList, 30);
    insertAtHead(&myList, 20);
    insertAtHead(&myList, 10);
    printf("当前链表长度: %d\n", myList.length);
    // 调用 ListTraverse 函数来打印整个链表
    ListTraverse(&myList);
    return 0;
}

6 运行结果

将以上代码编译并运行,你会得到如下输出:

当前链表长度: 3
开始遍历链表: 10 -> 20 -> 30 -> NULL

进阶:使用函数指针

上面的 ListTraverse 功能比较固定,只能打印数据,如果我们想让它更通用,比如既能打印,又能进行数据统计,该怎么办?

这时,函数指针 就派上用场了,我们可以将 ListTraverse 的行为参数化,让调用者决定对每个节点做什么操作。

1 定义操作函数类型

我们定义一个函数指针类型,这个类型的函数接收一个 int(节点数据)作为参数,没有返回值。

// 定义一个函数指针类型,它指向一个接受int参数、无返回值的函数
typedef void (*VisitFunc)(int);

2 改进后的 ListTraverse

我们修改 ListTraverse 函数,让它接收一个函数指针作为参数。

/**
 * @brief 遍历链表并对每个节点执行指定的操作
 * @param list 要遍历的链表
 * @param visit 一个函数指针,指向对节点数据的操作函数
 */
void ListTraverseWithFunc(LinkedList *list, VisitFunc visit) {
    Node *current = list->head;
    while (current != NULL) {
        // 调用传入的函数,并传入当前节点的数据
        visit(current->data);
        current = current->next;
    }
    printf("NULL\n");
}

3 定义不同的操作函数

我们可以定义多个不同的操作函数,然后传递给 ListTraverseWithFunc

// 操作函数1:打印数据
void printData(int data) {
    printf("%d -> ", data);
}
// 操作函数2:判断数据是否大于15
void checkGreaterThan15(int data) {
    if (data > 15) {
        printf("%d (大于15) ", data);
    }
}

4 在 main 函数中测试

int main() {
    LinkedList myList;
    initList(&myList);
    insertAtHead(&myList, 30);
    insertAtHead(&myList, 20);
    insertAtHead(&myList, 10);
    printf("--- 使用函数指针的遍历示例 ---\n");
    // 场景1:打印所有数据
    printf("场景1: 打印所有数据\n");
    ListTraverseWithFunc(&myList, printData);
    // 输出: 10 -> 20 -> 30 -> NULL
    printf("\n场景2: 筛选并打印大于15的数据\n");
    ListTraverseWithFunc(&myList, checkGreaterThan15);
    // 输出: 20 (大于15) 30 (大于15) NULL
    return 0;
}

5 运行结果

--- 使用函数指针的遍历示例 ---
场景1: 打印所有数据
10 -> 20 -> 30 -> NULL
场景2: 筛选并打印大于15的数据
20 (大于15) 30 (大于15) NULL

使用函数指针,ListTraverse 的功能变得极其灵活和强大,这是 C 语言中实现回调机制的经典方式。


特性 简单 ListTraverse 带函数指针的 ListTraverse
核心思想 从头到尾,顺着 next 指针访问。 从头到尾,顺着 next 指针访问,但行为由外部函数决定。
实现方式 在函数内部直接处理数据(如 printf)。 在函数内部调用一个外部传入的函数指针。
优点 简单直观,适合固定操作。 高灵活性、可重用性,符合“开闭原则”(对扩展开放,对修改关闭)。
缺点 功能固定,无法复用。 需要额外定义操作函数,对初学者可能稍显复杂。
适用场景 简单脚本、一次性打印。 需要对链表进行多种操作(打印、查找、修改、统计等)的复杂程序。

ListTraverse 是链表操作的基础,掌握其基本实现后,强烈建议学习并使用函数指针版本来提升代码的健壮性和可扩展性。

-- 展开阅读全文 --
头像
织梦 cattree 示例
« 上一篇 01-02
dede 缩略图不识别jpeg
下一篇 » 01-03

相关文章

取消
微信二维码
支付宝二维码

目录[+]