左右边界: 循环不变量
1、严格定义边界的实际意义是什么
2、明确变量的含义
3、循环不变量
4、小数据量调试
int l=0, r=n-1; //在[l,r]的范围里操作,所以当l==r时,区间[l..r]依然是有效的
int l=0, r=n; //在[l,r)的范围里操作,所以当l==r时,区间[l..r)是无效的 [42,42)
数组:
数组的索引可以有语义,也可以没有语义。
增、删、改、查、 每一种数据结构都可以要实现其中的一部分。
capacity 容量 size 实际有多少元素,size=0是指向了第一个没有存放元素的索引,向数组末尾添加元素,也就等同于向size索引处添加元素。size=capacity是指数组空间已满。
合法的索引: index<0 || index>size (index=size是指从数组的最后插入一个元素,如果index>size,则中间会存在不是合法的元素,元素不是紧密排列的)
最后一个元素的索引是size-1
动态数组
容器: 可以放置“任何”数据类型
栈:
只能从一端添加元素,也只能从一端取出元素
栈顶
程序调用的系统栈
栈顶元素反映了在嵌套的层次关系中,最近的需要匹配的元素
队列:
只能从一端(队尾)添加元素,只能从另一端(队首)取出元素
循环队列: 队首front(指向队列中的第一个元素) 队尾tail(指向下一次新的元素入队时应该存储的位置) front=tali时队列为空 (tail+1)% c =fronts是队列为满
capaticy中,浪费了一个空间
假设队列有8个size大小,索引从7到0的变化是(index+1)% c
链表: 真正的动态数据结构
head:链表头,指向链表中的第一个节点
在链表头添加元素: node.next=head head=node
在链表中间添加元素(关键是找到要添加节点的前一个节点): node.next=pre.next prev.next=node
在链表末尾添加元素:
虚拟头节点: dummyHead 则链表的第一个元素是dummyHead.next指向的元素
链表元素的删除: pre.next=delNode.next delNode.next=NULL
链表和递归:
递归 本质上,将原来的问题,转化为更小的同一问题
递归的宏观语义: 递归函数就是一个函数,完成一个功能
递归的微观解读:
递归调用是有代价的 函数调用+系统栈空间
递归深度
二分搜索树: 是一颗二叉树 每个节点的值,大于其左子树的所有节点的值,小于其右子树所有节点的值
存储的元素必须有可比较性
前序遍历 深度优先遍历
中序遍历 排序后的结果
后序遍历 应用:为二分搜索树释放内存
层序遍历 广度优先遍历 借助队列
删除二分搜索树的最小值和最大值
集合:set
映射 Map
堆和优先队列
优先队列: 出队顺序和如入队顺序无关,和优先级有关
二叉堆: 二叉堆是一颗完全二叉树 堆中某个节点的值总是不大于其父节点的值
1、数组从1开始 parent(i)=i/2 left child(i)=2*i right child(i)=2*i+1
2、数组从0开始 parent(i)=(i-1)/2 left child(i)=2*i+1 right child(i)=2*i+2
线段树:
哈希表