C语言入门教程(2)数据结构

C语言数据结构入门教程:链表、栈与队列

一、前言

数据结构是计算机科学中一个非常重要的概念,它描述了数据的组织、存储和操作方式。C语言作为一种高效的编程语言,非常适合实现各种数据结构。本文将从零基础开始,详细介绍链表、栈和队列这三种常见的线性数据结构,帮助初学者快速入门。

二、链表

(一)链表的定义与特点

链表是一种动态数据结构,由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针。链表的特点如下:

• 动态性:链表的大小可以根据需要动态调整,不像数组那样需要预先分配固定大小的内存。

• 灵活性:插入和删除操作非常灵活,只需修改指针即可,无需移动大量数据。

• 缺点:随机访问效率低,需要从头开始逐个遍历节点。

链表有多种类型,包括单链表、双链表和循环链表。

(二)单链表的实现

1.节点定义

typedef struct Node {
    int data;                 // 数据域
    struct Node* next;        // 指针域,指向下一个节点
} Node;

2.初始化链表

Node* initList() {
    Node* head = (Node*)malloc(sizeof(Node)); // 创建头节点
    head->next = NULL;                        // 初始化为空链表
    return head;
}

3.插入节点

void insertNode(Node* head, int pos, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node)); // 创建新节点
    newNode->data = value;

    Node* p = head;
    for (int i = 0; i < pos; i++) {             // 找到插入位置的前一个节点
        p = p->next;
    }
    newNode->next = p->next;                    // 新节点指向下一个节点
    p->next = newNode;                          // 前一个节点指向新节点
}

4.删除节点

void deleteNode(Node* head, int pos) {
    Node* p = head;
    for (int i = 0; i < pos; i++) {             // 找到删除位置的前一个节点
        p = p->next;
    }
    Node* temp = p->next;                       // 保存要删除的节点
    p->next = temp->next;                       // 前一个节点指向下一个节点
    free(temp);                                 // 释放删除的节点
}

5.遍历链表

void traverseList(Node* head) {
    Node* p = head->next;                       // 跳过头节点
    while (p != NULL) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

(三)链表的应用场景

链表常用于实现动态数据集合,如动态数组、栈、队列等。它的灵活性使其在需要频繁插入和删除的场景中表现出色。

三、栈

(一)栈的定义与特点

栈是一种后进先出(LIFO)的线性数据结构,只允许在一端(栈顶)进行插入和删除操作。栈的特点如下:

• 后进先出:最后插入的元素最先被删除。

• 操作简单:主要操作包括入栈(Push)、出栈(Pop)和查看栈顶元素(Top)。

• 应用场景:括号匹配、递归实现、回溯算法等。

(二)栈的实现

栈可以用数组或链表实现。以下是基于链表的栈实现:

1.栈结构定义

typedef struct {
    Node* top; // 栈顶指针
} Stack;

2.初始化栈

void initStack(Stack* s) {
    s->top = NULL;
}

3.入栈操作

void push(Stack* s, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = s->top; // 新节点指向当前栈顶
    s->top = newNode;       // 更新栈顶为新节点
}

4.出栈操作

int pop(Stack* s) {
    if (s->top == NULL) {
        printf("Stack is empty!\n");
        return -1;
    }
    Node* temp = s->top;       // 保存栈顶节点
    int value = temp->data;    // 获取栈顶元素
    s->top = temp->next;       // 更新栈顶为下一个节点
    free(temp);                // 释放原栈顶节点
    return value;
}

5.查看栈顶元素

int top(Stack* s) {
    if (s->top == NULL) {
        printf("Stack is empty!\n");
        return -1;
    }
    return s->top->data;
}

(三)栈的应用场景

栈常用于解决括号匹配问题、递归实现、回溯算法等。例如,编译器利用栈来处理函数调用和返回。

四、队列

(一)队列的定义与特点

队列是一种先进先出(FIFO)的线性数据结构,允许在一端(队尾)插入元素,在另一端(队首)删除元素。队列的特点如下:

• 先进先出:最先插入的元素最先被删除。

• 操作简单:主要操作包括入队(Enqueue)、出队(Dequeue)和查看队首元素(Front)。

• 应用场景:任务调度、缓冲区管理、广度优先搜索等。

(二)队列的实现

队列可以用数组或链表实现。以下是基于链表的队列实现:

1.队列结构定义

typedef struct {
    Node* front; // 队首指针
    Node* rear;  // 队尾指针
} Queue;

2.初始化队列

void initQueue(Queue* q) {
    q->front = q->rear = NULL;
}

3.入队操作

void enqueue(Queue* q, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = NULL;

    if (q->rear == NULL) { // 队列为空
        q->front = q->rear = newNode;
    } else {
        q->rear->next = newNode; // 将新节点连接到队尾
        q->rear = newNode;       // 更新队尾指针
    }
}

4.出队操作

int dequeue(Queue* q) {
    if (q->front == NULL) {
        printf("Queue is empty!\n");
        return -1;
    }
    Node* temp = q->front;       // 保存队首节点
    int value = temp->data;      // 获取队首元素
    q->front = temp->next;       // 更新队首指针

    if (q->front == NULL) {      // 如果队列为空,更新队尾指针
        q->rear = NULL;
    }
    free(temp);                  // 释放原队首节点
    return value;
}

5.查看队首元素

int front(Queue* q) {
    if (q->front == NULL) {
        printf("Queue is empty!\n");
        return -1;
    }
    return q->front->data;
}

(三)队列的应用场景

队列常用于任务调度、缓冲区管理、广度优先搜索等。例如,操作系统利用队列来管理进程调度。

五、参考代码

完整的参考代码,供参考和实践:

单链表代码

#include <stdio.h>

#include <stdlib.h>

typedef struct Node {

    int data;

    struct Node* next;

} Node;

Node* initList() {

    Node* head = (Node*)malloc(sizeof(Node));

    head->next = NULL;

    return head;

}

void insertNode(Node* head, int pos, int value) {

    Node* newNode = (Node*)malloc(sizeof(Node));

    newNode->data = value;

    Node* p = head;

    for (int i = 0; i < pos; i++) {

        if (p->next == NULL) {

            printf("Position out of range!\n");

            free(newNode);

            return;

        }

        p = p->next;

    }

    newNode->next = p->next;

    p->next = newNode;

}

void deleteNode(Node* head, int pos) {

    Node* p = head;

    for (int i = 0; i < pos; i++) {

        if (p->next == NULL) {

            printf("Position out of range!\n");

            return;

        }

        p = p->next;

    }

    if (p->next == NULL) {

        printf("Position out of range!\n");

        return;

    }

    Node* temp = p->next;

    p->next = temp->next;

    free(temp);

}

void traverseList(Node* head) {

    Node* p = head->next;

    while (p != NULL) {

        printf("%d ", p->data);

        p = p->next;

    }

    printf("\n");

}

int main() {

    Node* head = initList();

    insertNode(head, 0, 10);

    insertNode(head, 1, 20);

    insertNode(head, 2, 30);

    printf("List: ");

    traverseList(head);

    deleteNode(head, 1);

    printf("After deletion: ");

    traverseList(head);

    return 0;

}

栈的代码实现

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node* next;
} Node;

typedef struct {
    Node* top;
} Stack;

void initStack(Stack* s) {
    s->top = NULL;
}

void push(Stack* s, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = s->top;
    s->top = newNode;
}

int pop(Stack* s) {
    if (s->top == NULL) {
        printf("Stack is empty!\n");
        return -1;
    }
    Node* temp = s->top;
    int value = temp->data;
    s->top = temp->next;
    free(temp);
    return value;
}

int top(Stack* s) {
    if (s->top == NULL) {
        printf("Stack is empty!\n");
        return -1;
    }
    return s->top->data;
}

int main() {
    Stack s;
    initStack(&s);

    push(&s, 10);
    push(&s, 20);
    push(&s, 30);

    printf("Top element: %d\n", top(&s));
    printf("Popped element: %d\n", pop(&s));
    printf("Top element after pop: %d\n", top(&s));

    return 0;
}

队列的代码实现

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node* next;
} Node;

typedef struct {
    Node* front;
    Node* rear;
} Queue;

void initQueue(Queue* q) {
    q->front = q->rear = NULL;
}

void enqueue(Queue* q, int value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = NULL;

    if (q->rear == NULL) {
        q->front = q->rear = newNode;
    } else {
        q->rear->next = newNode;
        q->rear = newNode;
    }
}

int dequeue(Queue* q) {
    if (q->front == NULL) {
        printf("Queue is empty!\n");
        return -1;
    }
    Node* temp = q->front;
    int value = temp->data;
    q->front = temp->next;

    if (q->front == NULL) {
        q->rear = NULL;
    }
    free(temp);
    return value;
}

int front(Queue* q) {
    if (q->front == NULL) {
        printf("Queue is empty!\n");
        return -1;
    }
    return q->front->data;
}

int main() {
    Queue q;
    initQueue(&q);

    enqueue(&q, 10);
    enqueue(&q, 20);
    enqueue(&q, 30);

    printf("Front element: %d\n", front(&q));
    printf("Dequeued element: %d\n", dequeue(&q));
    printf("Front element after dequeue: %d\n", front(&q));

    return 0;
}

七、拓展

拓展练习:

• 链表的逆序:实现一个函数,将链表的顺序反转。

• 栈的最小值操作:扩展栈的功能,使其支持在常数时间内获取当前栈的最小值。

• 队列的优先级实现:实现一个优先级队列,支持按优先级出队。

如果有任何问题或需要进一步的解释,请随时提问!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值