面试题——数据结构

数组

  • 寻找数组中第二小的元素
    这里有很多方法可以实现:
    一个简单的解决方案是按递增顺序对数组进行排序,堆排、快排、归并排序等等都可以达到目的。排序数组中的前两个元素是两个最小的元素。这个解的时间复杂度是O(nlogn)。 关于排序算法后续会继续更新。
    更好的解决方案是扫描数组两次。在第一次遍历中找到最小元素。让这个元素为x,在第二次遍历中,找到最小的元素大于x,这个解的时间复杂度是O(n)。

当然有更好的方法就是,在一次遍历中找到最小的两个数,时间复杂度为O(n)
初始化2个最小值,firstmin,secondmin
遍历所有元素,假如当前元素小于firstmin,那么将更新firstmin,secondmin.如果小于secondmin直接更新secondmin

  • 找到数组中第一个不重复出现的整数
    思路一:空间换时间,用另外一个数组存储每个数字出现的次数,但题目只需要找到第一个不重复出现的数,故浪费空间,时间复杂度O(N^2)

思路二:双循环,只要找到第一个不重复的数组,循环终止,内层循环只要发现有重复,即刻停止,时间复杂度是O(N^2)

  • 合并两个有序数组
    方法一: 将两个有序数组a和b容纳到另一个数组c中
    算法思想:创建一个新的数组c,此数组的大小大于或等于已知两个数组之和。通过比较两个数组中的元素,谁小就把谁放到空数组中,知道其中一个数组为空,最后把剩下的数组全部放到新创建的始祖中。
    方法二:有两个有序数组a和b,其中数组a的末尾有足够的空间容纳数组b,将数组b容纳到数组a中。
    将两个数组从末尾开始往前比较,比完之后放在数组a的最后
  • 重新排列数组中的正值和负值
    可以将正数和负数分离,然后将正数和负数依次交换。

  • 使用栈计算后缀表达式
    后缀表达式的求值规则为:从左到右扫描后缀表达式,如果遇到操作数,将其压入栈中,如果遇到操作符,则从栈中弹出两个操作数,计算结果,然后把结果入栈,直到遍历完后缀表达式,则计算完成,此时的栈顶元素即为计算结果。
    如上的后缀表达式求值过程为:
    (1) 初始化栈,栈顶指针为空;
    (2) 遇到操作数a,入栈;
    (3) 遇到操作数b,入栈;
    (4) 遇到操作符*,弹出栈中两个元素,计算结果入栈;
    (5) 遇到操作数c,入栈;
    (6) 遇到操作符d,入栈;
    (7) 遇到操作数e,入栈;
    (8) 遇到运算符/,弹出栈中两个元素,计算结果入栈;
    (9) 遇到操作符-,弹出栈中两个元素,计算结果入栈;
    (10) 遇到操作数f,入栈;
    (11) 遇到操作符*,弹出栈中两个元素,计算结果入栈;
    (12) 遇到操作符+,弹出栈中两个元素,计算结果入栈;

  • 对栈的元素进行排序
    从原始栈中以此弹出元素放入辅助栈中,每当将要压入的元素使得辅助栈不是升序排列时,就将辅助栈中的元素压入原始栈,直到辅助栈里的元素都小于当前要压入的元素,然后再压入当前元素。
    因为只能使用一个辅助栈,我们每次取出栈内元素的时候,就要与辅助栈的元素比较,将所有大于取出元素的辅助站元素全部放回原栈之中,
    一直重复这个操作,就能最后得到一个排好序的栈。

  • 判断表达式是否括号平衡
    利用栈的特点,遇到 左括号 ( ,则入栈;
    遇到右括号 ) ,则出栈。注意出栈时检查栈是否为空。

队列

  • 使用队列表示栈
    栈实现队列:思路是有两个栈,一个用来放数据(数据栈),一个用来辅助(辅助栈)。数据添加时,会依次压人栈,取数据时肯定会取栈顶元素,但我们想模拟队列的先进先出,所以就得取栈底元素,那么辅助栈就派上用场了,把数据栈的元素依次弹出到辅助栈,但保留最后一个元素,最后数据栈就剩下了最后一个元素,直接把元素返回,这时数据栈已经没有了数据。最后呢,把辅助栈的元素依次压人数据栈,这样,我们成功取到了栈底元素。
    队列实现栈
    思路同上:有数据队列和辅助队列,模拟栈的先进后出,队列是队尾进队头出,也就是说每次取值要取队列的队尾元素,数据队列出队到辅助队列,留下最后一个元素返回,辅助队列再把元素出队到数据队列
  • 对队列的前k个元素倒序
    需要使用一个栈和一个新队列来实现反转队列前k个元素

1、从原始队列中取出k个元素,分别压入栈中

2、从栈中弹出所有元素逐个添加到一个新队列

3、把原始队列中剩下的元素也添加到新队列中

  • 使用队列生成从1到n的二进制数

链表

  • 反转链表
    参考
    反转单链表的思路:新建一个链表,然后原链表做头删操作,然后对新链表做头插操作。先定义一个新的head头指针标记为new head,初始化为空,然后定义一个node指针指向原链表头指针head。然后对原链表做头删操作,让head指向他的next的节点。然后这时候第一个节点已经被切割下来。然后再对新的链表做头插操作,让node指针的next指向新链表的头指针new head,然后完成头插操作。再更新new head作为新链表的头结点,再进行下一次循环。最终head指针指向原链表的结尾,退出循环,链表翻转完毕,最后返回新链表的newhead就可以。

  • 检测链表中的循环
    参考
    两个方法:一个是哈希表法,还有一个是快慢指针,哈希表法就是把节点的内存地址作为哈希值来存储起来,然后每遍历一个节点,就在这个结构当中查找是否被遍历过,是否有重复,如果有重复,就说明链表当中有循环,如果直到遍历结束也没有重复,就代表没有循环。使用哈希表的话它的时间复杂度是O(n),因为遍历操作需要O(n),因为它需要额外的哈希表的存储空间,所以空间复杂度也是O(n)。第二个是快慢指针,就是先定一个快指针,每次移动两个节点,然后定一个慢指针,每次移动一个节点,如果快指针能够追上慢指针,就说明有循环,否则就没有。这个方法的时间复杂度是O(n),空间复杂度是O(1)。

  • 返回链表倒数第N个节点
    参考
    两种方法,第一个方法就是计算链表的长度为L,然后打印链表从开头起的(L-N+1)个节点。第二个方法就是使用两个指针,分别是P1和P2,将他们先初始化指向head结点,然后P1从头开始移动N个节点,然后再将P1和P2一起往前移动,直到P1到达终点,就是指向空为止,这时候P2就是指向的是倒数第N个节点,返回P2即可.

  • 删除链表中的重复项
    解题思路:
    对链表进行循环遍历,以链表当前节点不为NULL作为循环的条件。遇到相同的值节点,将该值进行记录,并对链表中与记录值相同的节点进行删除操作。为了将剩余节点连接起来,需要记录删除节点的前一个节点,以此节点的next指向删除节点后的值不等节点。

解题步骤:
1.判断传入链表指针是否为空指针或空链表,如果为空直接返回;
2.定义两个节点,一个节点cur指针指向首节点,另一个节点prev指向空;
3.以cur!=NULL作为循环条件,进入while循环;
4.定义一个节点指针next指向cur->next,一个标志符needDelete初始化为false,表示节点是否需要删除
5.比较cur->data与next->data值的大小,如果相等,表示需要被删除,记录需要删除的值,进行删除操作,
如果不相等,改变prev与cur的指向
6.删除操作:定义Tobedel节点指针指向cur,如果Tobedel->value等于待删除的值,使next = Tobedel->next,删除节点 Tobedel,使Tobedel指向next ,进行下一波循环,直到Tobedel->value不等于待删除值结束 。结束 后,进行对prev的0 判空 ,为空指向*head = next,不为空执行prev->next = next,最后使cur指向next,进入下一波的循环。

实现广度和深度优先搜索
检查图是否为树
计算图的边数
找到两个顶点之间的最短路径

  • 求二叉树的高度
    参考
  • 在二叉搜索树中查找第k个最大值
    参考
  • 查找与根节点距离k的节点
    参考
  • 在二叉树中查找给定节点的祖先节点
    参考

哈希表

在数组中查找对称键值对
追踪遍历的完整路径
查找数组是否是另一个数组的子集
检查给定的数组是否不相交

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 把一个链表反向,递归,非递归都写一遍。 1.试编写3个函数实现   (1)建立一个双向链表   (2)插入一个节点   (3)删除一个节点 2.自己定义数据结构,写出程序:二叉树的前序遍历。 3.实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。 4.下面哪种排序法对12354最快 a quick sort b.buble sort c.merge sort 5.哪种结构,平均来讲,获取一个值最快 a. binary tree b. hash table c. stack 6.一个二叉树的三种遍历方法的输出结果 7.链表按升序打印每打印完一个节点就将该节点从链表删除 8.选择一种算法来整理出一个链接表。你为什么要选择这种方法?现在用o(n)时间来做。 9. 用一种算法在一个循环的链接表里插入一个节点,但不得穿越链接表。    10.给两个变量,如何找出一个带环单链表是什么地方出现环的? 11.哈希表和数组的定义,区别,优缺点。 12.链接表和数组之间的区别是什么? 任选一门语言,当场定义二叉排序树数据结构,写出两个函数:初始化,删除一个节点,20分钟 13. 递归的折半查找算法[不限语言] 14. 解释一下什么是B+树,如何实现B+树的查找和插入.(用图示) 15.实现双向链表删除一个节点P,在节点P后插入一个节点,写出这两个函数。 13.排序方法比较 (intel) 排序方法 平均时间 最坏时间 辅助存储 直接插入排序 O(N2) O(N2) O(1) 起泡排序 O(N2) O(N2) O(1) 快速排序 O(Nlog2N) O(N2) O(Nlog2N) 简单选择排序 O(N2) O(N2) O(1) 堆排序 O(Nlog2N) O(Nlog2N) O(1) 归并排序 O(Nlog2N) O(Nlog2N) O(n) 基数排序 O(d(n+radix)) O(d(n+radix)) O(radix) 17.一个链表的操作,注意代码的健壮和安全性。要求: (1)增加一个元素; (2)获得头元素; (3)弹出头元素(获得值并删除)。 18.内排序算法 19.折半查找的复杂度,证明 20.sizeof()和strlen()的使用. 21.顺序存储结构的优点,散列法的思想是什么? 22.汉罗塔算法,不能递归... 23.一个链表的结点结构 struct Node { int data ; Node *next ; }; typedef struct Node Node ; (1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel) (2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表 依然有序。 (3)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表 依然有序,这次要求用递归方法进行。 ( Autodesk) 24.编最优化Bubble(int *pIntArray,int L),要求:交换元素不能用临时变量,如果有序需要最优。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值