C语言进阶知识概览(一)

简介: 教程来源 https://app-adtysnu98v0h.appmiaoda.com 系统梳理C语言进阶核心知识:深度剖析多级指针、函数指针与const组合;详解动态内存管理、内存池及泄漏检测;实现链表、栈、队列、二叉搜索树等数据结构;涵盖内存布局、文件I/O、预处理与系统编程,助你突破瓶颈,成为真正精通C的开发者。

当你已经掌握了C语言的基础语法,能够编写简单的程序时,真正的挑战才刚刚开始。C语言进阶要求你深入理解内存管理、指针的高级用法、数据结构实现、编译链接过程、系统级编程等核心领域。本文将系统梳理C语言进阶开发的核心知识体系,涵盖指针深度剖析、动态内存管理、数据结构实现、文件系统操作、预处理高级技巧、多文件项目组织、系统调用等关键领域,助你突破瓶颈,成为一名真正精通C语言的开发者。
13f32e75-a8de-4be2-8800-387ce68cf0e4.png

一、指针深度剖析:C语言的灵魂
1.1 多级指针与指针数组

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

/**
 * 多级指针:指向指针的指针
 * 应用场景:动态二维数组、函数参数中修改指针本身
 */
void multi_level_pointer_demo() {
    int value = 100;
    int *ptr = &value;      // 一级指针
    int **pptr = &ptr;      // 二级指针
    int ***ppptr = &pptr;   // 三级指针

    printf("value = %d\n", value);
    printf("*ptr = %d\n", *ptr);
    printf("**pptr = %d\n", **pptr);
    printf("***ppptr = %d\n", ***ppptr);

    // 修改值
    ***ppptr = 200;
    printf("\n修改后 value = %d\n", value);
}

/**
 * 指针数组 vs 数组指针
 * 指针数组:数组元素是指针
 * 数组指针:指向数组的指针
 */
void pointer_array_vs_array_pointer() {
    // 1. 指针数组:存储指针的数组
    int a = 10, b = 20, c = 30;
    int *ptrArray[3] = {&a, &b, &c};  // 指针数组

    printf("指针数组:\n");
    for (int i = 0; i < 3; i++) {
        printf("ptrArray[%d] = %d\n", i, *ptrArray[i]);
    }

    // 2. 数组指针:指向数组的指针
    int arr[5] = {1, 2, 3, 4, 5};
    int (*arrayPtr)[5] = &arr;  // 指向包含5个int的数组

    printf("\n数组指针:\n");
    for (int i = 0; i < 5; i++) {
        printf("(*arrayPtr)[%d] = %d\n", i, (*arrayPtr)[i]);
    }

    // 3. 字符串数组(指针数组的典型应用)
    char *fruits[] = {"苹果", "香蕉", "橙子", "葡萄"};
    int fruitCount = sizeof(fruits) / sizeof(fruits[0]);

    printf("\n字符串数组:\n");
    for (int i = 0; i < fruitCount; i++) {
        printf("水果:%s\n", fruits[i]);
    }
}

/**
 * 函数指针的高级应用
 */
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }

// 函数指针作为参数(回调函数)
int calculate(int (*operation)(int, int), int x, int y) {
    return operation(x, y);
}

// 返回函数指针的函数
typedef int (*Operation)(int, int);
Operation get_operation(char op) {
    switch (op) {
        case '+': return add;
        case '-': return subtract;
        case '*': return multiply;
        case '/': return divide;
        default: return NULL;
    }
}

void function_pointer_demo() {
    // 函数指针数组(计算器)
    Operation ops[] = {add, subtract, multiply, divide};
    char symbols[] = {'+', '-', '*', '/'};

    printf("\n函数指针数组计算器:\n");
    for (int i = 0; i < 4; i++) {
        printf("10 %c 5 = %d\n", symbols[i], ops[i](10, 5));
    }

    // 动态选择操作
    Operation op = get_operation('*');
    printf("\n10 * 5 = %d\n", op(10, 5));

    // 回调函数
    printf("回调:5 + 3 = %d\n", calculate(add, 5, 3));
}

/**
 * 指向函数的指针数组(状态机实现)
 */
typedef enum {
    STATE_IDLE,
    STATE_RUNNING,
    STATE_PAUSED,
    STATE_STOPPED
} State;

void handle_idle() { printf("空闲状态\n"); }
void handle_running() { printf("运行状态\n"); }
void handle_paused() { printf("暂停状态\n"); }
void handle_stopped() { printf("停止状态\n"); }

void state_machine_demo() {
    void (*state_handlers[])(void) = {
        handle_idle,
        handle_running,
        handle_paused,
        handle_stopped
    };

    State current = STATE_RUNNING;
    state_handlers[current]();  // 调用对应处理函数
}

1.2 复杂指针声明解析

/**
 * 复杂指针声明解析
 * 规则:从变量名开始,先右后左,括号优先
 */
void complex_pointer_declaration() {
    // 1. 指针数组:int *p[10] → p是数组,包含10个指向int的指针
    int *p1[10];

    // 2. 数组指针:int (*p)[10] → p是指针,指向包含10个int的数组
    int (*p2)[10];

    // 3. 函数指针:int (*p)(int, int) → p是指针,指向返回int、参数(int,int)的函数
    int (*p3)(int, int);

    // 4. 返回指针的函数:int* p(int) → p是函数,返回int*
    int* p4(int);

    // 5. 函数指针数组:int (*p[5])(int) → p是数组,元素是函数指针
    int (*p5[5])(int);

    // 6. 指向函数指针数组的指针:int (*(*p)[5])(int)
    int (*(*p6)[5])(int);

    // 使用cdecl工具解析复杂声明
    // 安装:sudo apt install cdecl
    // 使用:cdecl> explain "int (*(*foo)(int))[5]"
}

/**
 * 使用typedef简化复杂声明
 */
typedef int (*OperationFunc)(int, int);        // 函数指针类型
typedef int (*ArrayOfFuncs[10])(int, int);     // 函数指针数组类型
typedef int (*FuncReturningArray())[10];       // 返回数组指针的函数

1.3 指针与const的深度结合

/**
 * const与指针的组合
 * const修饰的是它左边最近的内容,如果左边没有则修饰右边
 */
void const_pointer_demo() {
    int a = 10, b = 20;

    // 1. 指向常量的指针:不能通过指针修改值,但指针可以指向其他变量
    const int *ptr1 = &a;
    // *ptr1 = 30;  // 错误!不能修改指向的值
    ptr1 = &b;      // 可以,指针可以重新指向

    // 2. 常量指针:指针本身不能修改,但可以修改指向的值
    int *const ptr2 = &a;
    *ptr2 = 30;     // 可以,修改指向的值
    // ptr2 = &b;   // 错误!指针不能重新指向

    // 3. 指向常量的常量指针:都不能修改
    const int *const ptr3 = &a;
    // *ptr3 = 30;  // 错误!
    // ptr3 = &b;   // 错误!

    // 4. const在函数参数中的应用
    // void print_array(const int arr[], int size)  // 保证不修改数组
    // const char *str  // 字符串常量,常用于函数参数
}

/**
 * 常量字符串与字符数组的区别
 */
void string_const_demo() {
    // 字符串常量:存储在只读数据段,不能修改
    const char *str1 = "Hello World";
    // str1[0] = 'h';  // 错误!字符串常量不能修改

    // 字符数组:存储在栈上,可以修改
    char str2[] = "Hello World";
    str2[0] = 'h';  // 正确
    printf("修改后:%s\n", str2);

    // 字符串常量池
    const char *s1 = "Hello";
    const char *s2 = "Hello";
    printf("s1和s2指向同一地址?%s\n", s1 == s2 ? "是" : "否");  // 通常为"是"
}

二、动态内存管理深入
2.1 内存布局与分配策略

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

/**
 * C程序内存布局
 * 
 * 栈(Stack):局部变量、函数参数、返回地址,向下增长
 * 堆(Heap):动态分配的内存,向上增长
 * 数据段(Data Segment):
 *   - .data:已初始化的全局变量和静态变量
 *   - .bss:未初始化的全局变量和静态变量(自动初始化为0)
 * 代码段(Text Segment):可执行代码,只读
 */

// 全局变量(数据段 .data)
int global_init = 100;

// 未初始化全局变量(数据段 .bss)
int global_uninit;

// 静态变量(数据段 .data)
static int static_var = 50;

void memory_layout_demo() {
    // 局部变量(栈)
    int local_var = 10;
    int *heap_var = (int*)malloc(sizeof(int));

    printf("代码段地址:%p\n", (void*)memory_layout_demo);
    printf("全局变量地址:%p\n", (void*)&global_init);
    printf("静态变量地址:%p\n", (void*)&static_var);
    printf("局部变量地址:%p\n", (void*)&local_var);
    printf("堆变量地址:%p\n", (void*)heap_var);

    free(heap_var);
}

/**
 * 内存对齐与结构体大小
 */
struct __attribute__((packed)) PackedStruct {
    char c;     // 1字节
    int i;      // 4字节
    short s;    // 2字节
};  // 不按对齐规则,大小为7

struct NormalStruct {
    char c;     // 1 + 3填充
    int i;      // 4
    short s;    // 2 + 2填充
};  // 大小12字节

void memory_alignment_demo() {
    printf("PackedStruct大小:%zu\n", sizeof(struct PackedStruct));
    printf("NormalStruct大小:%zu\n", sizeof(struct NormalStruct));

    // 查看偏移量
    struct NormalStruct ns;
    printf("偏移量 c: %zu\n", offsetof(struct NormalStruct, c));
    printf("偏移量 i: %zu\n", offsetof(struct NormalStruct, i));
    printf("偏移量 s: %zu\n", offsetof(struct NormalStruct, s));
}

2.2 内存池实现

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

/**
 * 内存池(Memory Pool)
 * 预分配大块内存,自定义分配策略,减少malloc/free调用
 */
typedef struct MemoryBlock {
    void *start;
    size_t size;
    size_t used;
    struct MemoryBlock *next;
} MemoryBlock;

typedef struct MemoryPool {
    MemoryBlock *first_block;
    size_t block_size;
} MemoryPool;

// 创建内存池
MemoryPool* mempool_create(size_t block_size) {
    MemoryPool *pool = (MemoryPool*)malloc(sizeof(MemoryPool));
    if (!pool) return NULL;

    pool->first_block = NULL;
    pool->block_size = block_size;
    return pool;
}

// 分配新块
static MemoryBlock* mempool_alloc_block(MemoryPool *pool) {
    MemoryBlock *block = (MemoryBlock*)malloc(sizeof(MemoryBlock));
    if (!block) return NULL;

    block->start = malloc(pool->block_size);
    if (!block->start) {
        free(block);
        return NULL;
    }

    block->size = pool->block_size;
    block->used = 0;
    block->next = pool->first_block;
    pool->first_block = block;

    return block;
}

// 从内存池分配内存
void* mempool_alloc(MemoryPool *pool, size_t size) {
    if (!pool) return NULL;

    // 对齐到8字节
    size = (size + 7) & ~7;

    // 查找有足够空间的块
    MemoryBlock *block = pool->first_block;
    while (block) {
        if (block->size - block->used >= size) {
            void *ptr = (char*)block->start + block->used;
            block->used += size;
            return ptr;
        }
        block = block->next;
    }

    // 没有足够空间,分配新块
    block = mempool_alloc_block(pool);
    if (!block) return NULL;

    if (block->size - block->used >= size) {
        void *ptr = (char*)block->start + block->used;
        block->used += size;
        return ptr;
    }

    return NULL;  // 单个块不够大
}

// 释放内存池(一次性释放所有内存)
void mempool_destroy(MemoryPool *pool) {
    if (!pool) return;

    MemoryBlock *block = pool->first_block;
    while (block) {
        MemoryBlock *next = block->next;
        free(block->start);
        free(block);
        block = next;
    }
    free(pool);
}

// 测试内存池
void memory_pool_demo() {
    MemoryPool *pool = mempool_create(1024 * 1024);  // 1MB块

    int *arr = (int*)mempool_alloc(pool, 100 * sizeof(int));
    char *str = (char*)mempool_alloc(pool, 256);

    // 使用内存...
    for (int i = 0; i < 100; i++) {
        arr[i] = i;
    }
    strcpy(str, "Hello from memory pool!");
    printf("%s\n", str);

    mempool_destroy(pool);  // 一次性释放所有
}

2.3 内存泄漏检测

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

/**
 * 简单的内存泄漏检测工具
 */
typedef struct Allocation {
    void *ptr;
    size_t size;
    const char *file;
    int line;
    struct Allocation *next;
} Allocation;

static Allocation *allocations = NULL;
static size_t total_allocated = 0;

void* track_malloc(size_t size, const char *file, int line) {
    void *ptr = malloc(size);
    if (ptr) {
        Allocation *alloc = (Allocation*)malloc(sizeof(Allocation));
        alloc->ptr = ptr;
        alloc->size = size;
        alloc->file = file;
        alloc->line = line;
        alloc->next = allocations;
        allocations = alloc;
        total_allocated += size;
    }
    return ptr;
}

void track_free(void *ptr) {
    Allocation **curr = &allocations;
    while (*curr) {
        if ((*curr)->ptr == ptr) {
            Allocation *to_free = *curr;
            *curr = (*curr)->next;
            total_allocated -= to_free->size;
            free(to_free);
            break;
        }
        curr = &((*curr)->next);
    }
    free(ptr);
}

void print_memory_report() {
    if (allocations) {
        printf("内存泄漏检测报告:\n");
        printf("================================\n");
        Allocation *curr = allocations;
        while (curr) {
            printf("泄漏:%p 大小 %zu 字节 (分配于 %s:%d)\n",
                   curr->ptr, curr->size, curr->file, curr->line);
            curr = curr->next;
        }
        printf("总泄漏内存:%zu 字节\n", total_allocated);
    } else {
        printf("无内存泄漏\n");
    }
}

// 使用宏替换malloc和free
#define malloc(size) track_malloc(size, __FILE__, __LINE__)
#define free(ptr) track_free(ptr)

void memory_leak_test() {
    int *leak1 = (int*)malloc(100 * sizeof(int));
    int *leak2 = (int*)malloc(200 * sizeof(int));
    free(leak1);
    // leak2 没有释放
}

// 注意:需要在main函数最后调用print_memory_report()

三、数据结构实现
3.1 链表(单链表、双链表、循环链表)

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

// 单链表节点
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 创建节点
Node* create_node(int data) {
    Node *new_node = (Node*)malloc(sizeof(Node));
    if (!new_node) return NULL;
    new_node->data = data;
    new_node->next = NULL;
    return new_node;
}

// 单链表操作
typedef struct LinkedList {
    Node *head;
    Node *tail;
    size_t size;
} LinkedList;

void linkedlist_init(LinkedList *list) {
    list->head = NULL;
    list->tail = NULL;
    list->size = 0;
}

void linkedlist_push_front(LinkedList *list, int data) {
    Node *new_node = create_node(data);
    if (!new_node) return;

    new_node->next = list->head;
    list->head = new_node;
    if (!list->tail) {
        list->tail = new_node;
    }
    list->size++;
}

void linkedlist_push_back(LinkedList *list, int data) {
    Node *new_node = create_node(data);
    if (!new_node) return;

    if (!list->tail) {
        list->head = new_node;
        list->tail = new_node;
    } else {
        list->tail->next = new_node;
        list->tail = new_node;
    }
    list->size++;
}

void linkedlist_insert(LinkedList *list, int index, int data) {
    if (index < 0 || index > list->size) return;

    if (index == 0) {
        linkedlist_push_front(list, data);
        return;
    }

    if (index == list->size) {
        linkedlist_push_back(list, data);
        return;
    }

    Node *new_node = create_node(data);
    if (!new_node) return;

    Node *curr = list->head;
    for (int i = 0; i < index - 1; i++) {
        curr = curr->next;
    }
    new_node->next = curr->next;
    curr->next = new_node;
    list->size++;
}

int linkedlist_pop_front(LinkedList *list) {
    if (!list->head) return 0;

    Node *to_free = list->head;
    int data = to_free->data;
    list->head = list->head->next;
    if (!list->head) {
        list->tail = NULL;
    }
    free(to_free);
    list->size--;
    return data;
}

void linkedlist_print(LinkedList *list) {
    Node *curr = list->head;
    while (curr) {
        printf("%d -> ", curr->data);
        curr = curr->next;
    }
    printf("NULL\n");
}

void linkedlist_free(LinkedList *list) {
    Node *curr = list->head;
    while (curr) {
        Node *next = curr->next;
        free(curr);
        curr = next;
    }
    list->head = NULL;
    list->tail = NULL;
    list->size = 0;
}

// 双链表节点
typedef struct DNode {
    int data;
    struct DNode *prev;
    struct DNode *next;
} DNode;

typedef struct DoublyLinkedList {
    DNode *head;
    DNode *tail;
    size_t size;
} DoublyLinkedList;

void dlist_push_back(DoublyLinkedList *list, int data) {
    DNode *new_node = (DNode*)malloc(sizeof(DNode));
    if (!new_node) return;
    new_node->data = data;
    new_node->prev = list->tail;
    new_node->next = NULL;

    if (list->tail) {
        list->tail->next = new_node;
    } else {
        list->head = new_node;
    }
    list->tail = new_node;
    list->size++;
}

void dlist_print_forward(DoublyLinkedList *list) {
    DNode *curr = list->head;
    while (curr) {
        printf("%d <-> ", curr->data);
        curr = curr->next;
    }
    printf("NULL\n");
}

void dlist_print_backward(DoublyLinkedList *list) {
    DNode *curr = list->tail;
    while (curr) {
        printf("%d <-> ", curr->data);
        curr = curr->prev;
    }
    printf("NULL\n");
}

void linkedlist_demo() {
    LinkedList list;
    linkedlist_init(&list);

    linkedlist_push_back(&list, 10);
    linkedlist_push_back(&list, 20);
    linkedlist_push_front(&list, 5);
    linkedlist_insert(&list, 2, 15);

    printf("单链表:");
    linkedlist_print(&list);
    printf("大小:%zu\n", list.size);

    linkedlist_pop_front(&list);
    printf("弹出头部后:");
    linkedlist_print(&list);

    linkedlist_free(&list);
}

3.2 栈与队列

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

// 栈(数组实现)
typedef struct Stack {
    int *data;
    int top;
    int capacity;
} Stack;

Stack* stack_create(int capacity) {
    Stack *s = (Stack*)malloc(sizeof(Stack));
    if (!s) return NULL;
    s->data = (int*)malloc(capacity * sizeof(int));
    if (!s->data) {
        free(s);
        return NULL;
    }
    s->top = -1;
    s->capacity = capacity;
    return s;
}

bool stack_is_empty(Stack *s) {
    return s->top == -1;
}

bool stack_is_full(Stack *s) {
    return s->top == s->capacity - 1;
}

void stack_push(Stack *s, int value) {
    if (stack_is_full(s)) {
        // 动态扩容
        s->capacity *= 2;
        s->data = (int*)realloc(s->data, s->capacity * sizeof(int));
        if (!s->data) return;
    }
    s->data[++s->top] = value;
}

int stack_pop(Stack *s) {
    if (stack_is_empty(s)) return 0;
    return s->data[s->top--];
}

int stack_peek(Stack *s) {
    if (stack_is_empty(s)) return 0;
    return s->data[s->top];
}

void stack_free(Stack *s) {
    if (s) {
        free(s->data);
        free(s);
    }
}

// 队列(循环数组实现)
typedef struct Queue {
    int *data;
    int front;
    int rear;
    int capacity;
    int size;
} Queue;

Queue* queue_create(int capacity) {
    Queue *q = (Queue*)malloc(sizeof(Queue));
    if (!q) return NULL;
    q->data = (int*)malloc(capacity * sizeof(int));
    if (!q->data) {
        free(q);
        return NULL;
    }
    q->front = 0;
    q->rear = 0;
    q->capacity = capacity;
    q->size = 0;
    return q;
}

bool queue_is_empty(Queue *q) {
    return q->size == 0;
}

bool queue_is_full(Queue *q) {
    return q->size == q->capacity;
}

void queue_enqueue(Queue *q, int value) {
    if (queue_is_full(q)) {
        // 动态扩容
        int new_capacity = q->capacity * 2;
        int *new_data = (int*)malloc(new_capacity * sizeof(int));
        if (!new_data) return;

        // 重新排列元素
        for (int i = 0; i < q->size; i++) {
            new_data[i] = q->data[(q->front + i) % q->capacity];
        }
        free(q->data);
        q->data = new_data;
        q->front = 0;
        q->rear = q->size;
        q->capacity = new_capacity;
    }
    q->data[q->rear] = value;
    q->rear = (q->rear + 1) % q->capacity;
    q->size++;
}

int queue_dequeue(Queue *q) {
    if (queue_is_empty(q)) return 0;
    int value = q->data[q->front];
    q->front = (q->front + 1) % q->capacity;
    q->size--;
    return value;
}

void queue_free(Queue *q) {
    if (q) {
        free(q->data);
        free(q);
    }
}

// 栈应用:括号匹配
bool is_balanced(const char *str) {
    Stack *s = stack_create(100);

    for (int i = 0; str[i] != '\0'; i++) {
        char c = str[i];
        if (c == '(' || c == '[' || c == '{') {
            stack_push(s, c);
        } else if (c == ')' || c == ']' || c == '}') {
            if (stack_is_empty(s)) {
                stack_free(s);
                return false;
            }
            char top = stack_pop(s);
            if ((c == ')' && top != '(') ||
                (c == ']' && top != '[') ||
                (c == '}' && top != '{')) {
                stack_free(s);
                return false;
            }
        }
    }

    bool result = stack_is_empty(s);
    stack_free(s);
    return result;
}

void stack_queue_demo() {
    Stack *s = stack_create(10);
    stack_push(s, 1);
    stack_push(s, 2);
    stack_push(s, 3);
    printf("栈弹出:%d\n", stack_pop(s));
    printf("栈顶:%d\n", stack_peek(s));
    stack_free(s);

    Queue *q = queue_create(3);
    queue_enqueue(q, 10);
    queue_enqueue(q, 20);
    queue_enqueue(q, 30);
    queue_enqueue(q, 40);  // 扩容
    printf("队列弹出:%d\n", queue_dequeue(q));
    queue_free(q);

    printf("括号匹配 '([{}])':%s\n", is_balanced("([{}])") ? "匹配" : "不匹配");
    printf("括号匹配 '([)]':%s\n", is_balanced("([)]") ? "匹配" : "不匹配");
}

3.3 二叉树与遍历

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

// 二叉树节点
typedef struct TreeNode {
    int data;
    struct TreeNode *left;
    struct TreeNode *right;
} TreeNode;

// 创建节点
TreeNode* create_node(int data) {
    TreeNode *node = (TreeNode*)malloc(sizeof(TreeNode));
    if (!node) return NULL;
    node->data = data;
    node->left = NULL;
    node->right = NULL;
    return node;
}

// 插入二叉搜索树
TreeNode* bst_insert(TreeNode *root, int data) {
    if (root == NULL) {
        return create_node(data);
    }

    if (data < root->data) {
        root->left = bst_insert(root->left, data);
    } else if (data > root->data) {
        root->right = bst_insert(root->right, data);
    }
    return root;
}

// 查找节点
TreeNode* bst_search(TreeNode *root, int data) {
    if (root == NULL || root->data == data) {
        return root;
    }

    if (data < root->data) {
        return bst_search(root->left, data);
    }
    return bst_search(root->right, data);
}

// 查找最小值
TreeNode* bst_find_min(TreeNode *root) {
    while (root && root->left) {
        root = root->left;
    }
    return root;
}

// 删除节点
TreeNode* bst_delete(TreeNode *root, int data) {
    if (root == NULL) return NULL;

    if (data < root->data) {
        root->left = bst_delete(root->left, data);
    } else if (data > root->data) {
        root->right = bst_delete(root->right, data);
    } else {
        // 找到要删除的节点
        if (root->left == NULL) {
            TreeNode *temp = root->right;
            free(root);
            return temp;
        } else if (root->right == NULL) {
            TreeNode *temp = root->left;
            free(root);
            return temp;
        }

        // 有两个子节点:找到右子树的最小节点
        TreeNode *min_node = bst_find_min(root->right);
        root->data = min_node->data;
        root->right = bst_delete(root->right, min_node->data);
    }
    return root;
}

// 前序遍历(根-左-右)
void preorder_traversal(TreeNode *root) {
    if (root) {
        printf("%d ", root->data);
        preorder_traversal(root->left);
        preorder_traversal(root->right);
    }
}

// 中序遍历(左-根-右)——二叉搜索树得到有序序列
void inorder_traversal(TreeNode *root) {
    if (root) {
        inorder_traversal(root->left);
        printf("%d ", root->data);
        inorder_traversal(root->right);
    }
}

// 后序遍历(左-右-根)
void postorder_traversal(TreeNode *root) {
    if (root) {
        postorder_traversal(root->left);
        postorder_traversal(root->right);
        printf("%d ", root->data);
    }
}

// 层序遍历(使用队列)
void levelorder_traversal(TreeNode *root) {
    if (!root) return;

    // 简单队列实现
    TreeNode *queue[100];
    int front = 0, rear = 0;
    queue[rear++] = root;

    while (front < rear) {
        TreeNode *node = queue[front++];
        printf("%d ", node->data);

        if (node->left) queue[rear++] = node->left;
        if (node->right) queue[rear++] = node->right;
    }
}

// 计算树的高度
int tree_height(TreeNode *root) {
    if (root == NULL) return 0;
    int left_height = tree_height(root->left);
    int right_height = tree_height(root->right);
    return (left_height > right_height ? left_height : right_height) + 1;
}

// 释放树
void tree_free(TreeNode *root) {
    if (root) {
        tree_free(root->left);
        tree_free(root->right);
        free(root);
    }
}

void binary_tree_demo() {
    TreeNode *root = NULL;
    int values[] = {50, 30, 70, 20, 40, 60, 80, 10, 25, 35, 45};
    int n = sizeof(values) / sizeof(values[0]);

    for (int i = 0; i < n; i++) {
        root = bst_insert(root, values[i]);
    }

    printf("前序遍历:");
    preorder_traversal(root);
    printf("\n");

    printf("中序遍历:");
    inorder_traversal(root);
    printf("\n");

    printf("后序遍历:");
    postorder_traversal(root);
    printf("\n");

    printf("层序遍历:");
    levelorder_traversal(root);
    printf("\n");

    printf("树的高度:%d\n", tree_height(root));

    printf("查找40:%s\n", bst_search(root, 40) ? "找到" : "未找到");

    root = bst_delete(root, 50);
    printf("删除50后中序遍历:");
    inorder_traversal(root);
    printf("\n");

    tree_free(root);
}

来源:
https://app-adtysnu98v0h.appmiaoda.com

相关文章
|
1天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
10222 33
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
14天前
|
人工智能 安全 Linux
【OpenClaw保姆级图文教程】阿里云/本地部署集成模型Ollama/Qwen3.5/百炼 API 步骤流程及避坑指南
2026年,AI代理工具的部署逻辑已从“单一云端依赖”转向“云端+本地双轨模式”。OpenClaw(曾用名Clawdbot)作为开源AI代理框架,既支持对接阿里云百炼等云端免费API,也能通过Ollama部署本地大模型,完美解决两类核心需求:一是担心云端API泄露核心数据的隐私安全诉求;二是频繁调用导致token消耗过高的成本控制需求。
5903 14
|
21天前
|
人工智能 JavaScript Ubuntu
5分钟上手龙虾AI!OpenClaw部署(阿里云+本地)+ 免费多模型配置保姆级教程(MiniMax、Claude、阿里云百炼)
OpenClaw(昵称“龙虾AI”)作为2026年热门的开源个人AI助手,由PSPDFKit创始人Peter Steinberger开发,核心优势在于“真正执行任务”——不仅能聊天互动,还能自动处理邮件、管理日程、订机票、写代码等,且所有数据本地处理,隐私完全可控。它支持接入MiniMax、Claude、GPT等多类大模型,兼容微信、Telegram、飞书等主流聊天工具,搭配100+可扩展技能,成为兼顾实用性与隐私性的AI工具首选。
23113 119
|
7天前
|
人工智能 JavaScript API
解放双手!OpenClaw Agent Browser全攻略(阿里云+本地部署+免费API+网页自动化场景落地)
“让AI聊聊天、写代码不难,难的是让它自己打开网页、填表单、查数据”——2026年,无数OpenClaw用户被这个痛点困扰。参考文章直击核心:当AI只能“纸上谈兵”,无法实际操控浏览器,就永远成不了真正的“数字员工”。而Agent Browser技能的出现,彻底打破了这一壁垒——它给OpenClaw装上“上网的手和眼睛”,让AI能像真人一样打开网页、点击按钮、填写表单、提取数据,24小时不间断完成网页自动化任务。
1883 4

热门文章

最新文章