1. 红黑树相关问题
- 能保证在最坏情况下,基本的动态几何操作的时间均为O(lgn)
- 红黑树的查找效果是有最低保证的。在最坏的情况下也可以保证O(logN)的,这是要好于二叉查找树的。因为二叉查找树最坏情况可以让查找达到O(N)。
- 如果你的数据分布较好,则比较宜于采用 AVL树(例如随机产生系列数),但是如果你想处理比较杂乱的情况,则红黑树是比较快的
2.常见排序算法总结
算法 | 最好时间 | 最坏时间 | 平均时间 | 额外空间 | 稳定性 |
---|---|---|---|---|---|
选择 | n2 | n2 | n2 | 1 | 不稳定 |
冒泡 | n | n2 | n2 | 1 | 稳定 |
插入 | n | n2 | n2 | 1 | 稳定 |
希尔 | n | n2 | n1.3(不确定) | 1 | 不稳定 |
归并 | nlog2n | nlog2n | nlog2n | n | 稳定 |
快排 | nlog2n | n2 | nlog2n | log2n至n | 不稳定 |
堆 | nlog2n | nlog2n | nlog2n | 1 | 不稳定 |
基数 | n*k | n*k | n*k | n+k | 稳定 |
3.对比一下数组和链表的优缺点。
- 数组:优点是支持随机访问,缺点是插入和删除效率低,内存空间要求高,必须有足够的连续内存空间。
- 链表:优点是插入删除速度快,内存利用率高,不会浪费内存。缺点是不能随机查找。
4. 两个栈模拟队列怎么实现?
假设有栈A和B,入队就直接进栈A,出队先看B,B不为空就直接栈顶元素出栈,否则先把A的所有元素出栈并进栈到B中,再弹出B的栈顶元素。
5. 如何优化快排使得它稳定?
暂时不想理
6. 快速排序是最快的排序算法吗?
快速排序的时间复杂度是基于比较的排序算法的最低的,也就是O(nlogn),但是特殊情形下是有线性排序的算法的,它们不是基于比较的,主要有计数排序,桶排序和基数排序。其中桶排序是稳定的,是常见排序里最快的一种,但桶排序是有要求的,就是数组元素隶属于固定(有限的)的区间,如范围为[0-9] (考试分数为1-100等)。
参考 比较型排序与非比较型排序算法的总结
7. 了解迪杰斯特拉算法吗?作用是什么?描述一下计算步骤。可以求得最优解吗?了解启发式搜索吗?
8. A星算法?
9. 如何评价一个哈希函数的质量?发生冲突如何处理?
评价哈希函数优劣的因素有:
- 能否将关键字均匀影射到哈希空间上
- 有无好的解决冲突的方法
- 计算哈希函数是否简单高效
哈希冲突的解决方法包括:
- 开放定址法(包括线行探查法,平方探查法等)
- 链地址法
- 再哈希法
10. 求top k的几种方法?
答:1)小顶堆的方法:O(nlogK) 的复杂度,如果 K 远小于 n 的话, O(nlogK) 其实就接近于 O(n) 了。优点是需要的内存比较小。
2)快排的 partition 划分:时间复杂度是 O(n),需要内存比较多。
参考 算法必学:经典的 Top K 问题
11.如何判断一个链表是否带环?
快慢指针法,详见《剑指Offer》
12.不使用第三个数交换两个数
void swap(int& a,int& b)
{
a = a^b;
b = a^b;
a = a^b;
}
13.快排最坏情况什么时候出现?如何避免?
这个答案还得看枢轴(pivot)的选择策略。在快速排序的早期版本中呢,最左面或者是最右面的那个元素被选为枢轴,那最坏的情况就会在下面的情况下发生啦:
- 数组已经是正序(same order)排过序的。
- 数组已经是倒序排过序的。
- 所有的元素都相同(1、2的特殊情况)
因为这些案例在用例中十分常见,所以这个问题可以通过要么选择一个随机的枢轴,或者选择一个分区中间的下标作为枢轴,或者(特别是对于相比更长的分区)选择分区的第一个、中间、最后一个元素的中值作为枢轴。有了这些修改,那快排的最差的情况就不那么容易出现了,但是如果输入的数组最大(或者最小元素)被选为枢轴,那最坏的情况就又来了。
14.手写快排
#include<stdio.h>
//交换函数
void swap(int &a, int &b)
{
int t = a;
a = b;
b = t;
}
int partition(int a[], int low, int high)
{
int x = a[low]; //将该数组第一个元素设置为比较元素
int i = low; //指向数组头的指针
int j = high; //指向数组尾的指针
while (i < j)
{
while (i < j && a[j] >= x)
j--; //从右至左找到第一个小于比较元素的数
while (i < j && a[i] <= x)
i++; //从左至右找到第一个大于比较元素的数
/*需要注意的是,这里的j--与i++的顺序不可以调换!
如果调换了顺序,i会走过头,以至于将后面较大的元素交换到数组开头*/
//将大数与小数交换
if (i != j)
swap(a[i], a[j]);
}
swap(a[low], a[i]); //将比较元素交换到期望位置
return i; //返回比较元素的位置
}
void quicksort(int a[], int low, int high)
{
if (low < high)
{
int i = partition(a, low, high); //划分数组并获取比较元素的位置
quicksort(a, low, i - 1); //对比较元素左边进行排序
quicksort(a, i + 1, high); //对比较元素右边进行排序
}
}
int main()
{
int a[] = { 5,7,1,6,4,8,3,2 };
int length = sizeof(a) / sizeof(a[0]);
quicksort(a, 0, length - 1);
for (int i = 0; i < length; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
15. 图的存储方式
1、邻接矩阵(数组)
2、邻接表(链表)
3、邻接多重表(链表)
4、十字链表(链表)
参考 数据结构—图的存储方式