学习算法第二天:栈队列和并查集、哈希表

栈和队列

•定义:存放数据的线性表

•操作:入栈/队列、出栈/队列、判断满/空

•空间复杂度:O(n)

•单次操作时间复杂度:O(1)

•区别  先进后出(FILO, First In Last Out) 先进先出(FIFO, First In First Out)

 

栈和队列的实现方式:数组和链表皆可(线性表)

•指针(辅助变量)栈顶/底指针     队头/尾指针

•关键:出入元素的同时移动指针

三、栈的应用

括号匹配:

•括号、引号等符号是成对出现的,必须相互匹配

•设计一个算法,自动检测输入的字符串中的括号是否匹配

•比如:{}[([][])] 匹配      [(])不匹配    (()]不匹配

从左向右扫描字符串

当前是[,期待一个]

当前是(,和刚才的[不匹配,说明相匹配的符号还在右边,继续扫描

当前是[,和刚才的(不匹配,说明相匹配的符号还在右边,继续扫描

当前是],和刚才的[正好一对,可以从字符串中“删去”不考虑了

当前是[,目前最近的一个是(,不匹配,继续扫描

当前是],和刚才的[正好一对,可以从字符串中“删去”不考虑了

当前是),目前最近的一个是(,正好一对,可以从字符串中“删去”不考虑了

当前是],目前最近的一个是[,正好一对,可以从字符串中“删去”不考虑了,此时左右的括号都匹配成功

总结:从上述过程看,由于括号很多,并不知道最后的括号是什么,所以采用流处理方式,先进来的括号反而是最后删除的,所以是先进后出,所以要用栈实现,如下:

依次类推,直至栈为空;

应用2:四则运算,加减乘除等,平常四则运算如:4*(5-2)+8属于中缀表达式 需要解析为后缀表达式:452-*8+;其中需要两个栈:数字栈和运算符栈。中缀表达式“9+(3-1)*3+10/2”转化为后缀表达式为“9 3 1- 3 * + 10 2 / +”.

1,数字直接入栈

2,如果是(因为还没匹配到括号所以直接入栈

3,如果是符合就和栈顶元素比,如果小于等于符合栈栈顶元素,则符号栈顶元素出栈压入数字栈,直到符合栈顶元素<当前符合优先级为止。

4,如果是)则直接出栈,直至出栈元素为匹配的括号为止。


人工栈模拟系统栈

因为系统栈可能内存溢出。递归隐式的栈调用,无出栈入栈操作,转为显示的栈调用。

1,递归是两步,一是调用跳转,二是返回back,需要明确

2,空间提前开辟,一个是当前值一个是返回值

如下求n!弄清楚边界条件,跳转做什么,返回做什么就好。

里层if语句:当n<=1时,返回值是1,开始往回返回。

外层if语句:往回走发生的事情是,f(n-1)算完了,所以是出栈*f(n-1);

继续往里走的事情是n进栈,然后跳转n-1;

结论:附加了进栈和出栈操作;以及是跳转还是返回的判断;外加栈为空的循环。

递归很多,全排列,求组合,并把排列和组合结果输出,8皇后,汉诺塔

设计一个队列/栈
支持:出,入,求最大元素
要求所有操作O(1)
一个例子:
3 in, 4 in, 2 in, 5 in, out, out, 6 in, out, out, out
思路:用两个栈计算,一个数据栈,一个最大元素栈,后续每个元素入栈时,与最大栈中栈顶元素比较,若入栈元素data 大于最大栈栈顶元素,则把data同时压入两个栈中,若data小于最大元素栈中栈顶元素,则只压入栈数据栈中。出栈时,判断两个栈顶元素是否相等,若相等则两个栈同时执行出栈操作,不相等则,只有数据栈执行出栈操作。
并查集
定义:
存放数据的集合关系,如{1,2}{3,4}{5}
支持操作
•     建立新集合
•     查找某个元素属于哪个集合
•     合并两个集合
均摊时间复杂度近似O(1)
 
并查集的应用:
• 假设n个节点,初始时点与点之间没有连接
给出一系列的连接操作
一次连接操作不产生环,则接受,否则被抛弃
 
并查集的实现:
存储:使用数组标记每个元素属于的子集
index 1 2 3 4 5 6 7 8
         8 2 3 3 5 5 2 8
合并:直接将根节点属于的子集改变,根指向根,为什么操作根呢,因为叶子和叶子相互指向就会出现一个节点指向两个节点的情况,不好存储。叶子指向根也不好,因为少了一条边。
查找:从待查找节点倒推到根节点,即两个元素是否是一个集合,只要根一致就是一个集合。
优化:路径压缩
 
 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章