TAC终于过去第一周了,至少在课程和习题意义上来说如此。
怎么说呢,颇费了一些时间和精力吧,有苦有甜,很遗憾没能全AC过去,最终还是败在了那道最小(大)生成树上,尽管它只是一个简单的并查集而已。
但说实话,并查集在三个月前看姥姥和黑皮书时,也没有十分走心吧。现在唯一能得出的结论就是,光听课看书抄笔记是完全没用的,必须亲手实现才能留下一点点的印象。
哎,看过的东西又尘归尘土归土了。
但也不是完全一点印象也没有的,比如还记得父节点表示法。
其他的,还多亏有了代码模板和提示,以及充分的讨论,才能顺利理解题意给AC掉。说来也很不是滋味,毕竟用了人家的东西,无论是思想上还是代码上,都不算完全是自己的东西。这样一来从写作变成了完形填空,难度降低了好几个档。也许从零写起的话,恐怕会花更多的时间和精力,也无法达到现在这种情况吧。光是输入输出就能够我喝一大壶的。
另外本以为这门课零基础的小白也可以听懂,实际上才发现人家是默认你很熟悉C++和基本数据结构和算法的……C++不会,数据结构学的很水,完全不会算法,码量太少的我一下子就无处遁形了。现在能想到的办法只有死磕,也唯有死磕,才能熬出一片天地来。C++不会,就只好看参考手册和示例现学现卖,涉及到的数据结构,就回头翻书翻笔记再重温课程。具体实现不会的,好多问多探讨。然后实在做不出也只好听习题课老师的讲解了。当然最重要的是吸收内化,就少不了之后的总结归纳。希望还能有精力尝试全凭自己从零写完。
现在还是太菜了,但这正是努力变强最有力的理由。
废话就扯到这,现在就做个阶段小结吧。
【习题1.1】 栈
描述
实现一个栈,完成以下功能:
入栈
出栈
询问栈中位置Y是谁
一开始栈为空。栈中的位置从1开始(即栈底位置为1)。
输入
第一行一个整数n,表示操作个数。
接下来n行,每行第一个数字表示操作(见描述):
若为数字1,则接下来有一串字符串X,表示将X压入栈中。
若为数字2,表示弹出栈顶(保证栈非空),并输出出栈的这个人。
若为数字3,则接下来有一个整数Y,表示询问栈中位置Y是谁(保证位置Y合法),并输出名字。
输出
将所有操作2和操作3输出,一行一个。
输入样例
11
1 a
1 b
1 c
3 1
3 2
3 3
2
1 d
3 1
3 2
3 3
输出样例
a
b
c
c
a
b
d
限制
对于30%的数据,1 ≤ n ≤ 2000;
对于另30%的数据,没有操作3;
对于100%的数据,1 ≤ n ≤ 100000。
数据中出现的字符串只包含26个小写字母(无空格等分隔符),且长度不超过15。
字符串有可能重复。正如现实中可能有重名一样。
时间:1 sec
空间:256 MB
提示
[入栈和出栈都是操作着栈顶。]
[开一个大小为n的数组,记录栈顶的位置,入栈出栈就是将这栈顶加一减一,栈中某个位置Y在数组相应的下标就是Y。]
代码实现:https://paste.ubuntu.com/p/CxVg2kRk6b/
【总结】
这就是最基本数据结构 栈 的简单实现,没什么好说的。当时还有些窃喜,以为之后也会是这种程度。现在想想真是太傻了,如果真的只是这种程度,那这钱可真是白花了。
【习题1.2】 队列
描述
实现一个队列,完成以下功能:
入列
出列
询问队列中位置Y是谁
一开始队列为空。队列中的位置从1开始(即队头位置为1)。
输入
第一行一个整数n,表示操作个数。
接下来n行,每行第一个数字表示操作(见描述):
若为数字1,则接下来有一串字符串X,表示将X加入队列。
若为数字2,表示出列(保证队列非空),并输出出列的这个人。
若为数字3,则接下来有一个整数Y,表示询问队列中位置Y是谁(保证位置Y合法),并输出名字。
输出
将所有操作2和操作3输出,一行一个。
输入样例
11
1 a
1 b
1 c
3 1
3 2
3 3
2
1 d
3 1
3 2
3 3
输出样例
a
b
c
a
b
c
d
限制
对于30%的数据,1 ≤ n ≤ 2000;
对于另30%的数据,没有操作3;
对于100%的数据,1 ≤ n ≤ 100000。
数据中出现的字符串只包含26个小写字母(无空格等分隔符),且长度不超过15。
字符串有可能重复。正如现实中可能有重名一样。
时间:1 sec
空间:256 MB
提示
[队头出列,队尾入列。]
[开一个大小为n的数组,记录队头和队尾的位置,入列出列就是将这两个位置改变一下,队列中某个位置Y在数组相应的下标为队头的位置+Y-1。]
代码实现:https://paste.ubuntu.com/p/7sHDMxPWvs/
【总结】
同样也是最基本数据结构 队列 的实现,甚至都不是循环队列。
【习题1.3】二叉树
描述
给定一个1到n的排列,按顺序依次插入到一棵二叉排序树(即二叉搜索树)中,请你将这棵二叉树前序遍历和后序遍历输出。
输入
第一行一个整数n。
接下来一行表示为n个整数,代表1到n的一个排列。
输出
输出所建成的二叉树的前序遍历和后序遍历。
输入样例
10
2 6 9 3 5 7 10 8 4 1
输出样例
2 1 6 3 5 4 9 7 8 10
1 4 5 3 8 7 10 9 6 2
限制
对于50%的数据,1 ≤ n ≤ 100;
对于100%的数据,1 ≤ n ≤ 100000。
保证建成的树的高度不超过50。
时间:1 sec
空间:256 MB
提示
[二叉树的操作基本都是递归操作,只要想想如何在一个节点上判断是朝着左孩子走还是朝着右孩子走就行了。]
代码实现: (自己的)https://paste.ubuntu.com/p/4GK4C5vT5z/ (别人的)https://paste.ubuntu.com/p/cK5v8m7Dhf/
【总结】
做到这里,就开始有些阻力了。讨论区和群里对这题的讨论也不少。
最开始没读懂题,后来发现题目和模板都有了改动,从二叉树改成了二叉搜索树。若非如此,只给出先序和后序是无法唯一确定一颗树的。
一开始写的版本,用的是模板给出的数组顺序存储方式。之前顺序存储只学过完全二叉树,即根下标为1,左孩子下标是父节点的二倍。但这个方法的致命缺点是空间浪费严重,不足以解决特别大的数据。结果也是如此,跑到后面几个测点就发生了段错误,显然是爆栈了。
后来没办法, 只好自己写个结构体,换成链式存储,简单回顾了一下何头的先序后序,然后轻松地AC了。
但是显然还是没看懂模板是怎么用顺序存储的…不知道如何解决左右孩子如何表示。后来看了别人的代码,才发现自己把顺序和链式的思想混为一谈了,实际上并没有那么麻烦,也没有当时就处理左右孩子的必要。而且这方法对数组空间的利用率非常高,真的是名副其实的“顺序”存储。
(未完待续……)
原文地址:https://www.cnblogs.com/lilinilil/p/9058543.html