面试

查询与排序算法和数据结构

算法和数据结构是相辅相成的,通过选择合适的数据结构,可以优化存储和访问效率,而使用恰当的算法则能在操作数据时提高效率。两者的结合能够在不同场景中提供更好的性能。例如,在搜索问题中,哈希表能使查找操作更高效,而在排序问题中,选择合适的排序算法(如快速排序或归并排序)能显著提升程序的执行速度。

算法

时间复杂度和空间复杂度:理解算法效率,如何通过大O符号衡量。
数据结构:选择合适的数据结构(如数组、链表、堆、树、图)来优化算法。
排序和查找:如快速排序、归并排序、二分查找等经典算法。
动态规划与分治法:解决优化问题和递归问题的常见方法。
图算法:包括最短路径、最小生成树、深度优先搜索(DFS)和广度优先搜索(BFS)。
贪心算法:用于选择最优解的策略。

排序

冒泡排序(Bubble Sort)
通过不断交换相邻的未排序元素,将较大的元素“冒泡”到列表末尾。
时间复杂度:O(n²),因为每个元素都可能与其他所有元素交换。
空间复杂度:O(1),在原地进行交换。

适用于数据量小、元素大致有序的情况。性能不佳,不推荐用于大数据。


选择排序(Selection Sort)
每次选择未排序部分的最小元素,并与当前元素交换位置。
时间复杂度:O(n²),需要遍历所有元素找到最小值。
空间复杂度:O(1),原地排序。

适用于内存限制较小的情况,数据量较少时可使用。
注:相比冒泡排序选择排序与其对比次数相关,不同在于冒泡排序的交换次数可能要大于选择排序


插入排序(Insertion Sort)
将未排序的元素插入到已排序部分的正确位置。
时间复杂度:O(n²),最坏情况下每个元素都需要与已排序元素比较。
空间复杂度:O(1),原地排序。

适合数据量小或部分有序的数据集,例如在线实时排序。


快速排序(Quick Sort)
通过选择一个基准元素,将数组分成两部分,递归排序两部分。
时间复杂度:平均O(n log n),最坏O(n²)(当选的基准不理想时)。
空间复杂度:O(log n),递归调用栈的空间。

常用于大规模数据集,如数据库中的排序,效率高。
注:利用空间换时间,想像一下在最理想的情况下,每次都选中中值基准值时整个数据的散落情况就像下面一样:
			968745321
	4321 	    5   		9687
1 	 2 	   43   5      67     8     9	
比对次数:(8)+(3+3)+(2)= 16 < 9*(9-1)/2=36(冒泡)

极端情况:
968745321
1  	96874532
1 	2 	9687453
1 	2 	3 	968745
1 	2 	3 	4 	96875
1 	2 	3 	4 	5 	9687
1 	2 	3 	4 	5 	6 	987
1 	2 	3 	4 	5 	6 	7 	98
1 	2 	3 	4 	5 	6 	7 	8 	9

比对次数:8+7+6+5+4+3+2+1=36(退化为O(n²))


归并排序(Merge Sort)
通过将数组分成两部分,递归地排序,并将两个已排序的部分合并。
时间复杂度:O(n log n),分治法使得每次操作缩小问题规模。
空间复杂度:O(n),需要额外的数组存储合并结果。

适用于需要稳定排序的场景,特别是对外存数据排序。

注:归并排序与快速排序的先对比后排序相反,它是先分割再对比排序并组合。虽然它占用更多空间,速度也不如快速排序,但是直接对数据的分隔让它更适合并行化处理数据,对于大数据集(如Hadoop 和 Spark)与只能加载部分数据的大文件数据排序更有优势,同时它的排序方式也让它拥有稳定性1
堆排序:
时间复杂度:O(n log n)。
非稳定排序,适合大数据集且需要内存占用固定的情况。
应用于需要频繁查找最大或最小元素的场景,如优先队列、任务调度、图算法中的Dijkstra算法。

希尔排序:
时间复杂度:O(n log n)(最优情况下)。
插入排序的改进版,通过分组减少交换次数,适合中等大小的数据。
适用于中等规模的数组,特别是在嵌入式系统和一些有限资源的设备中。

计数排序:
时间复杂度:O(n+k)(n为数据大小,k为数据范围)。
适用于范围较小的整数排序。
广泛用于处理小整数范围的排序问题,如计数学生成绩、字母表排序等。

基数排序:
时间复杂度:O(nk)(n为数据个数,k为数字位数)。
适合处理整数或字符串,尤其是数据范围较大的情况。
用于排序整数、字符串或IP地址等,广泛应用于大数据处理、数据库索引构建等场景。

查找

线性查找(Linear Search)
逐个检查数组中的元素,直到找到目标元素。
时间复杂度:O(n),最坏情况下需要检查所有元素。
空间复杂度:O(1),只需要常数空间。

适用于小数据集或数据无序的情况。


二分查找(Binary Search)
在已排序数组中通过每次将搜索范围减半来查找目标元素。
时间复杂度:O(log n),每次将问题规模减少一半。
空间复杂度:O(1),不需要额外空间(在非递归实现时)。

适合在已排序数据中进行查找,如二分查找树、搜索引擎中查找已排序的索引。


哈希查找(Hash Search)
使用哈希表直接查找目标元素。
时间复杂度:O(1),哈希表允许常数时间内进行查找。
空间复杂度:O(n),需要额外的空间来存储哈希表。

用于需要快速查找且数据无序的情况,如缓存系统、数据库索引、词典查找等。

注:哈希查找其实是利用了数据结构的特性,通过哈希函数将数据映射到表中的位置,实现高效查找,但前提是哈希函数设计良好,且没有严重的碰撞。而二分查找适用于有序数据集,可以先对无序数据集进行排序。

数据结构

线性数据结构

数组 (Array):固定大小的顺序存储结构。

链表 (Linked List):由一系列节点组成,每个节点包含数据和指向下一个节点的指针。

栈 (Stack):先进后出(LIFO)的数据结构。

队列 (Queue):先进先出(FIFO)的数据结构。

非线性数据结构

树 (Tree):
二叉树、平衡树、红黑树等。
常用于实现优先队列(如堆)、搜索树、文件系统等。

图 (Graph):
有向图、无向图、加权图等。
常用于表示网络拓扑、社交网络等。

堆 (Heap):
一棵完全二叉树,满足堆的性质。
常用于实现优先队列、堆排序等。

哈希数据结构

哈希表 (Hash Table):通过哈希函数将数据存储在数组中,查找、插入和删除操作平均时间复杂度为 O(1)。

哈希映射 (HashMap):Java 中的具体实现,基于哈希表存储键值对,

哈希集合 (HashSet):基于哈希表实现的集合,存储唯一元素。

问题

1.冒泡、选择、插入排序有什么不同
2.快速、归并排序的实现
3.什么时候会用到二分法
  1. 稳定性指的是在排序过程中,相等的元素在排序后的相对顺序保持不变。也就是说,如果两个元素值相等,它们在排序后的顺序不会改变。 ↩︎

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注