ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

# 第三周周记:从组合类型到数据结构,正式踏入“结构化“世界

# 第三周周记:从组合类型到数据结构,正式踏入“结构化“世界 charc;};sizeof(union Data)取最大成员的大小。同一时刻只能有效使用一个成员写了一个再读另一个得到的是重新解释的二进制位。适用场景需要用同一段内存表示不同类型数据时比如硬件寄存器映射、类型标记的通用数据容器。1.4 枚举enum枚举就是给一组整数常量起名字提高可读性enumColor{RED,GREEN,BLUE};RED 0, GREEN 1, BLUE 2默认从0开始递增也可以手动指定值。比#define更好的地方在于枚举有类型检查调试时能看到符号名。1.5 typedef——给类型起别名typedef不是定义新类型而是给已有类型起个短名字typedefunsignedlongulong;typedefstructStudent{charname[20];intage;}Student;// 以后可以写 Student 而不写 struct Student这周写链表代码时大量用到 typedef比如typedefstructLNode{intdata;structLNode*next;}LNode,*LinkList;LinkList就是LNode*的别名这样函数参数写LinkList L比写struct LNode *L简洁多了。二、预处理与文件组织——编译之前的魔法教案152.1 预处理是什么C代码从源文件到可执行文件要经过预处理 → 编译 → 汇编 → 链接四个阶段。预处理发生在编译之前由预处理器处理所有#开头的指令。2.2 宏定义#define无参宏——文本替换#definePI3.14159#defineMAX_SIZE100带参宏——注意括号陷阱#defineSQUARE(x)((x)*(x))如果不加括号SQUARE(23)会变成23*23 11而不是25。这是宏最容易踩的坑。带参宏和函数的区别宏是文本替换没有类型检查、没有调用开销函数有类型安全但有函数调用开销宏参数可能被多次求值副作用问题2.3 条件编译条件编译让同一份源码可以根据条件编译出不同版本#ifdefDEBUGprintf(调试信息: x %d\n,x);#endif#ifVERSION2// V2功能#else// V1功能#endif常用指令#ifdef、#ifndef、#if、#elif、#else、#endif头文件防重复包含就是条件编译最经典的应用#ifndef__LIST_H__#define__LIST_H__// 头文件内容#endif2.4 文件包含#include#includestdio.h// 系统头文件在系统目录找#includelist.h// 自定义头文件先在当前目录找2.5 多文件组织真正项目不会把所有代码写在一个.c里。标准做法是.h头文件放声明函数原型、结构体定义、宏定义、外部变量声明.c源文件放实现编译时分别编译各.c文件最后链接在一起。三、数据结构概述与时间复杂度3.1 什么是数据结构数据结构是相互之间存在一种或多种特定关系的数据元素的集合。说白了就是研究数据怎么存、怎么组织。数据结构分两层逻辑结构数据之间的逻辑关系线性、树形、图状、集合物理结构存储结构数据在计算机里怎么存顺序存储、链式存储、索引存储、散列存储3.2 什么是算法算法是解决特定问题求解步骤的描述具有五个特性有穷性确定性可行性输入0个或多个输出1个或多个3.3 时间复杂度——BigO表示法衡量算法效率的标尺。用O(f(n))表示n是问题规模。推导规则用常数1取代所有加法常数只保留最高阶项最高阶项系数化为1常见时间复杂度排序从小到大复杂度名称典型场景O(1)常数阶数组下标访问O(log n)对数阶二分查找O(n)线性阶遍历数组O(n log n)线性对数阶快速排序、归并排序O(n²)平方阶冒泡排序、简单选择排序O(n³)立方阶矩阵乘法O(2ⁿ)指数阶汉诺塔递归空间复杂度类似衡量算法运行过程中额外占用的内存空间。四、线性表——数据结构的第一个正经结构4.1 线性表概念线性表n个具有相同特性的数据元素的有限序列。特点第一个元素无前驱最后一个元素无后继中间元素有且仅有一个前驱和一个后继元素之间是一对一的关系4.2 顺序表顺序表是线性表的顺序存储实现——用一段连续的内存空间依次存储数据元素。静态分配#defineMaxSize50typedefstruct{intdata[MaxSize];intlength;}SqList;数组大小固定编译时就确定不能扩展。动态分配typedefstruct{int*data;intMaxSize;intlength;}SeqList;用malloc动态申请内存用realloc扩容更灵活。4.3 顺序表基本操作插入在第i个位置插入元素从最后一个元素开始往后挪时间复杂度 O(n)删除删除第i个位置的元素从第i1个元素开始往前挪时间复杂度 O(n)按位查找直接下标访问O(1)按值查找从头遍历O(n)判空length 0清空length 0遍历for循环输出O(n)这周写了一道顺序表合并的练习题把两个有序顺序表 A 和 B 合并成有序顺序表 C。用的是双指针归并的思想时间复杂度 O(mn)。五、单链表5.1 为什么需要链表顺序表的优点是随机访问快O(1)下标访问但插入删除要大量移动元素。链表用链式存储解决了这个问题——元素可以散布在内存任意位置用指针串起来。5.2 单链表结构typedefstructLNode{intdata;structLNode*next;}LNode,*LinkList;带头结点vs不带头结点带头结点的链表头结点的next指向第一个数据结点这样插入/删除第一个位置的操作和其他位置统一不用特殊处理头指针。这周写的链表代码全部采用带头结点设计。5.3 单链表基本操作头插法建表新结点插在头结点后面结果和输入顺序相反尾插法建表新结点插在最后结果和输入顺序一致按位插入/删除找到第 i-1 个结点修改指针O(n)按值查找从头遍历比较O(n)遍历输出从头到尾走一遍O(n)求表长遍历计数销毁逐个 free 结点5.4 本周链表实战这周我写了一个完整的带头结点链表操作程序包含头插、尾插头删、尾删新增按位插入、按位删除、按位查找按值查找遍历、判空、清空、销毁踩了一个坑我用了两个结构体——HeadNode存 size next 指针和LNode存 data next 指针导致HeadNode*和LinkList即LNode*是不同类型GCC 15 编译器报了-Wincompatible-pointer-types错误。修复方式是遍历时从L-next第一个数据结点开始对第1个位置单独处理。还写了三道数据结构编程题顺序表合并双指针归并A{1,3,5,7,9} B{2,4,6,8,10} → C{1,2,…,10}有序链表构建输入10个无序整数用插入排序思想构建升序链表单链表就地逆置用头插法把每个结点重新插到头结点后面不额外开辟数据结点空间六、本周收获与反思知识体系搭建这周最大的收获是完成了从零散C语法到系统化数据结构的过渡领域本周内容C语言语法结构体、联合体、枚举、typedef、内存对齐C语言工程预处理宏/条件编译、多文件组织数据结构基础数据结构定义、算法定义、时间复杂度线性表顺序表静态/动态、单链表踩坑总结结构体类型不兼容不同结构体指针不能直接赋值即使成员一样。编译器是对的类型安全很重要。宏的括号陷阱带参宏每个参数和整体都要加括号不然运算优先级会出问题。链表头结点的好处统一了第一个位置的插入/删除逻辑写代码时少很多 if-else。下周计划继续深入单链表操作双向链表、循环链表开始学习栈和队列多写代码把每个操作都手写一
返回列表