2025-03-21 01:54:19 +08:00
2025-03-18 17:30:39 +08:00
2025-03-18 17:30:39 +08:00
2025-03-17 17:08:26 +08:00
2025-03-17 17:08:26 +08:00
2025-03-21 01:00:13 +08:00
2025-03-17 13:44:50 +08:00
2025-03-18 17:30:39 +08:00
2025-03-20 22:44:30 +08:00
2025-03-17 13:44:50 +08:00
2025-03-21 01:53:52 +08:00
2025-03-21 01:45:33 +08:00
2025-03-20 22:44:30 +08:00

数据结构与算法练习代码

项目目标

通过用C语言构建本学期所有数据结构和算法,来练编码.

项目结构说明

main.c由于测试和调用其它.c文件,其它算法源文件用其英文名命名,编写被调用文件时首先在name.h声名结构体和函数,然后在name.c实现功能.

示例

linked_list.h:

#ifndef LINKED_LIST_H
#define LINKED_LIST_H

#include <stdbool.h>

// 链表节点结构体
typedef struct Node {
  int data;
  struct Node* next;
} Node;

// 链表操作函数声明
Node* create_node(int data);
void append_node(Node** head, int data);
bool delete_node(Node** head, int data);
void print_list(const Node* head);
void free_list(Node** head);

#endif // LINKED_LIST_H

linked_list.c:

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

// 创建新节点
Node* create_node(int data) {
  Node* new_node = (Node*)malloc(sizeof(Node));
  if (!new_node) {
      fprintf(stderr, "内存分配失败\n");
      exit(EXIT_FAILURE);
  }
  new_node->data = data;
  new_node->next = NULL;
  return new_node;
}

// 在链表末尾添加节点
void append_node(Node** head, int data) {
  Node* new_node = create_node(data);
  if (*head == NULL) {
      *head = new_node;
      return;
  }
  Node* current = *head;
  while (current->next != NULL) {
      current = current->next;
  }
  current->next = new_node;
}

// 删除包含指定数据的节点
bool delete_node(Node** head, int data) {
  if (*head == NULL) {
      return false;
  }
  Node* current = *head;
  Node* previous = NULL;

  // 查找要删除的节点
  while (current != NULL && current->data != data) {
      previous = current;
      current = current->next;
  }

  // 未找到节点
  if (current == NULL) {
      return false;
  }

  // 删除节点
  if (previous == NULL) {
      // 要删除的是头节点
      *head = current->next;
  } else {
      previous->next = current->next;
  }
  free(current);
  return true;
}

// 打印链表
void print_list(const Node* head) {
  const Node* current = head;
  while (current != NULL) {
      printf("%d -> ", current->data);
      current = current->next;
  }
  printf("NULL\n");
}

// 释放链表内存
void free_list(Node** head) {
  Node* current = *head;
  while (current != NULL) {
      Node* next = current->next;
      free(current);
      current = next;
  }
  *head = NULL;
}

main.c:

#include <stdio.h>
#include "linked_list.h"

int main() {
    Node* head = NULL;
    insertNode(&head, 10);
    insertNode(&head, 20);
    insertNode(&head, 30);
    printList(head);
    deleteNode(&head, 20);
    printList(head);
    return 0;
}

补充

知识补充

#ifndef LINKED_LIST_H
#define LINKED_LIST_H  



#endif 

在 C 语言中,头文件(.h 文件)通常使用预处理指令 #ifndef#define#endif 来防止头文件被重复包含,避免编译错误。这种技术被称为 头文件保护符包含卫士

工作原理:

  1. #ifndef LINKED_LIST_H:检查宏 LINKED_LIST_H 是否未被定义。
  2. #define LINKED_LIST_H:如果未定义,则定义宏 LINKED_LIST_H
  3. 头文件内容:包含实际的类型定义和函数声明。
  4. #endif:结束条件编译。

当头文件第一次被包含时,LINKED_LIST_H 未被定义,编译器会处理头文件内容并定义 LINKED_LIST_H。如果头文件再次被包含,由于 LINKED_LIST_H 已被定义,#ifndef 条件不成立,编译器会跳过头文件内容,从而避免重复定义。

注意事项:

  • 宏名的唯一性:确保每个头文件的宏名唯一,通常使用头文件名的大写形式,并用下划线替代非字母数字字符。
  • #pragma once 指令:一些编译器支持 #pragma once,它可以防止头文件被多次包含,使用起来更简洁,但并非所有编译器都支持,使用 #ifndef 等预处理指令具有更好的可移植性。

通过使用头文件保护符,可以有效防止头文件的重复包含,确保代码的正确编译。

规则补充

统一使用小写下划线命名法

Description
No description provided
Readme 177 KiB
Languages
C 95.8%
Makefile 4.2%