数据结构-----初始数据结构、及GDB调试

一、数据结构核心概念

1. 数据结构定义
复制代码
// 嵌入式场景示例:传感器网络节点结构
struct SensorNode {
    uint16_t node_id;     // 2字节
    float temperature;    // 4字节
    uint32_t timestamp;    // 4字节
    struct SensorNode *next; // 指针(4/8字节)
}; // 总大小:14-18字节(需内存对齐)
  • 核心作用:在有限内存中高效组织传感器数据

二、数据结构分类体系

1. 逻辑结构
类型 特点 嵌入式应用场景
线性 一对一关系 串口数据缓冲队列
树型 一对多关系 文件系统目录结构
图状 多对多关系 物联网设备拓扑关系
集合 无特殊关系 寄存器位操作
2. 物理结构
类型 特点 嵌入式适用场景
顺序 连续内存存储 实时数据采集缓冲区
链式 指针链接存储 动态任务调度列表

三、嵌入式开发核心数据结构

1. 线性结构
复制代码
// 循环缓冲区实现(无动态内存分配)
#define BUF_SIZE 128
typedef struct {
    uint8_t data[BUF_SIZE];
    uint16_t head;
    uint16_t tail;
} CircularBuffer;

void buf_push(CircularBuffer *cb, uint8_t val) {
    cb->data[cb->head] = val;
    cb->head = (cb->head + 1) % BUF_SIZE;
}
2. 树形结构
复制代码
// 平衡二叉树节点(用于快速查找)
typedef struct TreeNode {
    int key;
    void *data;
    struct TreeNode *left;
    struct TreeNode *right;
    uint8_t height; // AVL树高度
} TreeNode;
3. 图结构
复制代码
// 稀疏图邻接表表示(适用于低功耗设备)
typedef struct EdgeNode {
    uint16_t dest;
    uint16_t weight;
    struct EdgeNode *next;
} EdgeNode;

typedef struct {
    EdgeNode **adjList;
    uint16_t numNodes;
} Graph;

四、算法设计与分析

1. 算法特性验证表
特性 验证方法 嵌入式特殊要求
有穷性 最大执行周期分析 满足硬实时截止期
确定性 单元测试覆盖所有条件分支 处理硬件异常分支
可行性 指令周期计算 避免浮点运算(无FPU设备)
高效性 最坏情况时间复杂度分析 限制栈深度防止溢出
2. 嵌入式算法设计原则
复制代码
// 内存优化示例:位域使用
typedef struct {
    uint8_t led_state : 1;   // 1位
    uint8_t fan_speed : 3;   // 3位
    uint8_t reserved  : 4;    // 4位
} DeviceStatus; // 总大小1字节

五、时间复杂度核心概念

1. 定义

算法时间复杂度用于描述算法运行时间与输入数据规模(n)之间的增长关系,反映算法的效率。

2. 大O表示法规则
步骤 操作说明 示例转换
1 用1取代所有加法常数项 T(n)=3n+5 → T(n)=3n+1
2 保留最高阶项 T(n)=3n²+2n+1 → 3n²
3 去除最高阶项的系数 3n² → O(n²)

六、常见时间复杂度类型

1. 复杂度等级对比
类型 数学表示 典型算法 嵌入式场景示例
常数时间 O(1) 数组索引访问 寄存器读写操作
对数时间 O(log n) 二分查找 平衡传感器数据查询
线性时间 O(n) 遍历数组 串口数据帧解析
线性对数时间 O(n log n) 快速排序 大数据量排序(慎用)
平方时间 O(n²) 冒泡排序 小规模数据排序
指数时间 O(2ⁿ) 穷举算法 密码破解(避免使用)

七、时间复杂度推导实战

1. 基础案例推导
复制代码
// 案例1:单循环结构
void func1(int n) {
    for(int i=0; i<n; i++) {  // 执行n次
        printf("%d\n", i);    // O(1)操作
    }
}

分析

  • 总操作次数 T(n) = n × 1 = n

  • 时间复杂度:O(n)

    // 案例2:嵌套循环结构
    void func2(int n) {
    for(int i=0; i<n; i++) { // n次循环
    for(int j=0; j<n; j++) { // n次循环
    printf("%d,%d\n",i,j); // O(1)操作
    }
    }
    }

分析

  • T(n) = n × n × 1 = n²
  • 时间复杂度:O(n²)

2. 复合结构推导
复制代码
// 案例3:混合复杂度结构
void func3(int n) {
    // 第一部分:O(n)
    for(int i=0; i<2n; i++) { 
        // O(1)操作
    }

    // 第二部分:O(log n)
    int k=1;
    while(k < n) {
        k *= 2;  // 每次循环规模减半
    }

    // 第三部分:O(1)
    printf("Done");
}

分析

  • T(n) = 2n + log₂n + 1
  • 应用规则:
    1. 替换常数项 → 2n + log₂n + 1
    2. 保留最高阶项 → 2n
    3. 去除系数 → n
  • 最终时间复杂度:O(n)

3. 递归算法推导
复制代码
// 案例4:二分递归
int fibonacci(int n) {
    if(n <= 1) return n;
    return fibonacci(n-1) + fibonacci(n-2);
}

分析

  • 递归树深度为n,每层产生2ⁿ个节点
  • T(n) ≈ 2ⁿ
  • 时间复杂度:O(2ⁿ)

八、特殊场景处理技巧

1. 最坏/平均情况分析
复制代码
// 快速排序时间复杂度分析
void quick_sort(int arr[], int low, int high) {
    if(low < high) {
        int pi = partition(arr, low, high);  // O(n)
        quick_sort(arr, low, pi-1);          // 递归左半部
        quick_sort(arr, pi+1, high);         // 递归右半部
    }
}
  • 最坏情况(已排序数组):O(n²)
  • 平均情况:O(n log n)
2. 均摊分析
复制代码
// 动态数组扩容操作
typedef struct {
    int *data;
    int size;
    int capacity;
} DynamicArray;

void push_back(DynamicArray *da, int val) {
    if(da->size == da->capacity) {
        // 扩容操作 O(n)
        da->capacity *= 2;
        int *new_data = realloc(da->data, da->capacity*sizeof(int));
        da->data = new_data;
    }
    da->data[da->size++] = val;  // O(1)
}
  • 单次扩容成本O(n),但均摊到n次操作为O(1)

九、嵌入式开发优化策略

1. 时间复杂度与内存权衡
算法选择 时间效率 内存消耗 适用场景
快速排序 O(n log n) O(log n) 内存充足的排序需求
插入排序 O(n²) O(1) 小规模数据排序
计数排序 O(n+k) O(k) 已知数值范围的整数排序
2. 实时系统注意事项
  • 避免不可预测的递归深度
  • 限制动态内存分配
  • 优先选择确定性算法

十、复杂度速查表

代码模式 时间复杂度 示例
单层循环 O(n) for(i=0; i<n; i++)
双层嵌套循环 O(n²) 冒泡排序
循环变量指数增长 O(log n) while(i<n) i*=2
分治算法(二分) O(n log n) 归并排序
全排列组合 O(n!) 旅行商问题穷举解法

十一、GDB调试环境准备

1. 编译选项
复制代码
# 基础调试编译 (生成符号表)
gcc -g main.c -o app

# 多线程程序调试
gcc -g -lpthread thread_demo.c -o thread_app

# 显示完整字符串内容(默认截断300字符)
(gdb) set print elements 0
2. 启动调试
复制代码
# 常规启动
gdb ./app

# 核心转储分析
gdb ./app core.dump

十二、核心调试流程

1. 基础调试流程
复制代码
(gdb) break main        # 主函数入口断点
(gdb) run               # 启动程序执行
(gdb) next              # 单步步过
(gdb) step              # 单步步入
(gdb) continue          # 继续执行到下一个断点
2. 断点管理
命令 功能说明
break fun.c:36 在fun.c第36行设置断点
break MyClass::method 类方法断点
info breakpoints 查看所有断点
disable 2 禁用2号断点
ignore 1 5 忽略1号断点前5次触发

十三、内存错误调试技巧

1. 段错误(Segmentation Fault)排查
复制代码
# 复现错误
(gdb) run
Program received signal SIGSEGV, Segmentation fault.

# 定位错误位置
(gdb) where
#0  0x0804894f in viewMediaList (path=0xbfff0ca "/home/linux") at fun.c:36
#1  0x0804878b in main () at main.c:33

# 检查关键变量
(gdb) frame 0            # 切换到出错栈帧
(gdb) print path         # 查看路径指针
(gdb) x/10x path         # 检查内存内容
2. 内存诊断命令
复制代码
(gdb) info registers     # 查看寄存器状态
(gdb) x/20wx \(  esp        # 查看栈内存
(gdb) watch *0x0804a000  # 设置内存监视点
(gdb) backtrace full     # 显示完整堆栈信息

十四、高级调试技巧

1. 多线程调试
复制代码
(gdb) info threads       # 显示所有线程
(gdb) thread 3           # 切换到3号线程
(gdb) break thr_func thread 2  # 特定线程断点
2. 条件断点
复制代码
(gdb) break fun.c:50 if count > 100
(gdb) condition 3 buffer != NULL
3. 数据可视化
复制代码
(gdb) print *array@10     # 打印数组前10元素
(gdb) set print pretty on # 结构化显示
(gdb) display var         # 持续监控变量

十五、典型调试场景示例

1. 缓冲区溢出检测
复制代码
(gdb) break strcpy
(gdb) commands
> print (char*)dest
> print (char*)src
> continue
end
2. 死锁定位
复制代码
(gdb) info threads
(gdb) thread apply all backtrace
(gdb) p mutex1->__data.__lock
3. 内存泄漏排查
复制代码
(gdb) break malloc
(gdb) commands
> set   \)ptr = (void*)\(  rax
> printf "Allocated %p\n",   \)ptr
> continue
end

(gdb) break free
(gdb) commands
> printf "Freed %p\n", (void*)\(  rdi
> continue
end

十六、调试流程总结

  1. 复现问题 :使用run触发错误
  2. 定位现场where查看调用栈
  3. 分析上下文frame切换栈帧,info locals查看局部变量
  4. 诊断内存x命令检查内存,watch设置监视点
  5. 修正验证:修改代码后重新编译测试
  6. 预防措施:添加断言和内存检查
相关推荐
小羊在奋斗2 分钟前
【算法】数组、链表、栈、队列、树
数据结构·算法
格格Code31 分钟前
数据结构——单循环链表clist
数据结构
BingLin-Liu3 小时前
图论之cruskal算法(克鲁斯卡尔)
数据结构·算法·图论
周Echo周5 小时前
8、STL中的map和pair使用方法
开发语言·数据结构·c++·考研·算法·leetcode·pat考试
随风7568 小时前
有多少小于当前数字的数字 力扣1365
数据结构·算法·leetcode
dot to one9 小时前
深入刨析C++ stl::stack 、stl::queue 及 priority_queue
c语言·开发语言·数据结构·c++·算法·visual studio
程序趣谈12 小时前
算法随笔_74: 不同路径_1
数据结构·python·算法
修修修也13 小时前
算法手记3
数据结构·学习·算法·刷题