这次回顾自己笔试中遇到的问题及反思,这些问题很多博客已经讲得非常清楚,学习了很多,大概归纳下自己学习的内容。
1、数组和链表
数组是静态分配内存,在一开始创建数组时,内存大小就已固定,数组创建默认初值为0,存储的地址是连续的。链表动态分配内存,根据后面的增删内存大小会有改变,链表的地址既可以是连续的,也可以是不连续的。
数组的根据下标查询数据所以,查询数据的时间复杂度为O(1),数组插入、删除都会对涉及到数组的后面(前面)元素的移位,时间复杂度为O(n);链表的查询会从第一个结点(不一定是头结点)开始查询,所以查询数据的时间复杂度为O(n),链表的插入、删除都只涉及一个元素,所以时间复杂度为O(1)。
数组优点:查询,修改快。缺点:插入、删除慢,内存固定,不能扩展,要求连续的内存地址。
链表优点:插入、删除快,内存动态分配,地址可不连续 缺点:查询、修改都需要从第一个节点遍历。
头结点与第一节点的区别:第一结点有可能为头结点,有可能不为头结点,因为头结点不是必须的。头结点是为了操作的通用和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(或者存放链表的长度),有了头结点对于第一个元素结点操作就和其他元素接点一致。
头指针为指向第一个结点的指针,若链表有头结点,则指向头结点,没有则指向第一个元素结点。头指针不为空,为必要元素。
2、单链表和双链表
单链表只有一个指向下一个结点的指针,而双向链表具有指向下一个结点和上一个结点的指针。单链表在删除某个结点,需要获取到要删除的结点的前驱,进行删除的方法有两种,一边定位要删除的结点,一边定位其前驱;先找到要删除的结点,再找到其前驱。双链表因为具有前后两个方向的指针,所以只需定位到删除的结点就可以。通常采用单链表是因为双链表多一个指针存储,在大规模存储下,人们通常采用时间换空间的方法。
3、冒泡算法
从小到大:第一轮,冒泡算法是通过第一个数据和第二个数据比较大小,将比较大的数据换到第二个数据位置,然后第二个数据和第三个数据比较大小,将更大的数据放到第三个位置,不断执行,总共执行n-1次(n为数组中的大小),之后最大的数据就会被存放到最后的位置。第二轮从第一个位置开始,总共执行n-2次,第三轮执行n-3次...总共执行的轮数为n-1轮。
4、选择排序算法
从小到大:第一轮,从所有元素中找到最小的元素,将最小的元素和第一个元素进行数值交换,第二轮对第二个元素到最后的元素查找最小的元素,然后将最小元素和第二个元素进行数值交换,第三轮...每一轮会选出最小的元素按顺序排放在在数组中。总共执行的轮数为n-1轮。
5、哈夫曼树
构建哈夫曼树首先对这串数字从小到大排序,然后然后取其中的两个最小的数字最为子叶,两个数字之和,再次添加到去掉了这两个数字的那串数字中,再次排序,再取其中两个最小的数字作为子叶:情况一,这两个最小的数字包含上一次两个数字之和,则在上层构建只有一个叶子节点的分支;情况二,不包含上一次最小数字之和,则是同一层次的两个叶子节点的分支。持续构造下去...带权路径长度为叶子结点所在第几层乘以叶子结点的权。
例如:1,2,3,5
第一次最小的两数:1,2 第二次最小的数为 3,3 (其中一个位前两最小数之和)
那么第二次的分叉就应该位于 1,2结点的上层。
6、笔试中遇到一个编程问题
(1)a[6]={1,-1,3,-2,0,2}
输出其中任意三个数字的和为0的组合,要求不重复。
做笔试的时候,脑袋被严重阻塞,完全没有分析好题目。昨晚睡觉前回想起这个问题发现就是一个组合问题。从数学的思维来讲就是,第一次,我从这六个数字中选出一个数字,然后第二次我再从剩余5个数字选出一个数字,第三次从剩余的4个数字选出一个数字,但是数学可以直接除去重复的数字,程序不行。不过程序也有好处,程序可以不需要随机性,直接遍历就ok,只要保证不遍历相同的数字就行。所以具体思路如下:
for(int i=0;i<=3;i++)//从第一个数字开始到第四个数字
for(int j=i+1;j<=4;j++)//从第一个数字的后一个数字到第五个数字
for(int k=j+1;k<=5;k++)//第一个数字的后两个数字开始到第六个数字
{
if(a[i]+a[j]+a[k]==0)
cout<<a[i]<<a[j]<<a[k]<<endl;
}
这样就能保证所有组合全部遍历过了,并且不会有相同的组合
(2)笔试只有这一道编程题,睡觉前想到了组合自然也就想到了排列,所以后来就思考了下排列如何实现,其实排列更简单,只要保证不要有两个及两个以上取到相同数字就可以了。具体方法如下:
for(int i=0;i<=5;i++)
for(int j=0;j<=5;j++)
{
if(j==i)
continue;
for(int k=0;k<=5;k++)
{
if(k==i||k==j)
continue;
if(a[i]+a[j]+a[k]==0)
cout<<a[i]<<a[j]<<a[k]<<endl;
}
}
链表相关内容主要学习了这个博客:https://blog.csdn.net/qq_26626709/article/details/52203924
讲得很仔细,如果有看到了这篇博客的同学不太了解链表的内容,可以参考学习。
以上,祝好。