1. Java常规排序有哪些分类?
正确回答通过率:82.0%
[ 详情 ] 推荐指数: ★★★★★ 试题难度: 初级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
排序可以分为内部排序和外部排序,在内存中进⾏的称为内部排序,当数据量很⼤时⽆法全部拷⻉到内 存需要使⽤外存,称为外部排序。
内部排序包括⽐较排序和⾮⽐较排序,⽐较排序包括插⼊/选择/交换/归并排序,⾮⽐较排序包括计数/ 基数/桶排序。
插⼊排序包括直接插⼊/希尔排序,选择排序包括直接选择/堆排序,交换排序包括冒泡/快速排序
2. 简述直接插入排序的原理 ?
正确回答通过率:76.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★★ 试题难度: 中级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
插入排序(Insertion sort)是一种简单直观且稳定的排序算法。
排序原理:
1.把所有的元素分为两组,已经排序的和未排序的;
2.找到未排序的组中的第一个元素,向已经排序的组中进行插入;
3.倒叙遍历已经排序的元素,依次和待插入的元素进行比较,直到找到一个元素小于等于待插入元素,那么就把待
插入元素放到这个位置,其他的元素向后移动一位;
2.交换第一个索引处和最小值所在的索引处的值
插入排序的时间复杂度分析
插入排序使用了双层for循环,其中内层循环的循环体是真正完成排序的代码,所以,我们分析插入排序的时间复杂度,主要分析一下内层循环体的执行次数即可。
最坏情况,也就是待排序的数组元素为{12,10,6,5,4,3,2,1},那么:
比较的次数为:(N-1)+(N-2)+(N-3)+...+2+1=((N-1)+1)(N-1)/2=N^2/2-N/2;
交换的次数为:(N-1)+(N-2)+(N-3)+...+2+1=((N-1)+1) (N-1)/2=N^2/2-N/2;
总执行次数为:(N2/2-N/2)+(N2/2-N/2)=N^2-N;
按照大O推导法则,保留函数中的最高阶项那么最终插入排序的时间复杂度为O(N^2)
3. 编写Java代码实现直接插入排序 ?
正确回答通过率:65.0%
[ 详情 ] 推荐指数: ★★★ 试题难度: 中级 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
// 插入排序
public class Insertion {
/*
对数组a中的元素进行排序
/
public static void sort(Comparable[] a) {
for (int i = 1; i < a.length; i++) {
for (int j = i; j > 0; j--) {
//比较索引j处的值和索引j-1处的值,如果索引j-1处的值比索引j处的值大,则交换数据,如果不大,那么就找到合适的位置了,退出循环即可;
if (greater(a[j - 1], a[j])) {
exch(a, j - 1, j);
} else {
break;
}
}
}
}
/
比较v元素是否大于w元素
/
private static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) > 0;
}
/
数组元素i和j交换位置
*/
private static void exch(Comparable[] a, int i, int j) {
Comparable temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
// 测试代码
public class InsertionTest {
public static void main(String[] args) {
Integer[] a = {
4, 3, 2, 10, 12, 1, 5, 6
}
;
Insertion.sort(a);
System.out.println(Arrays.toString(a));
//{1,2,3,4,5,6,10,12}
}
}
4. 简述冒泡排序的原理 ?
正确回答通过率:68.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★★ 试题难度: 中级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
冒泡排序:(Bubble Sort)是一种简单的交换排序。之所以叫做冒泡排序,因为我们可以把每个元素当成一个小气泡,根据气泡大小,一步一步移动到队伍的一端,最后形成一定对的顺序。
冒泡排序的原理:
我们以一个队伍站队为例,教官第一次给队员排队是无序的,这时候就需要排队,按矮到高的顺序排列,首先拎出第一第二个比较,如果第一个队员比第二个要高,则两个交换位置, 高的放到排到第二个位置,矮的就排到第一个,再把第二个,第三个比较,把高的排到后面一个位置,然后以此类推,直至第一轮所有队员都比较过一次(记住每次比较都是相邻的两个),这样就可以把最高的排到最后的位置。
总结就是:每一轮都需要从第一位开始进行相邻的两个数的比较,将较大的数放后面,比较完毕之后向后挪一位继续比较下面两个相邻的两个数大小关系,重复此步骤,直到最后一个还没归位的数。
5. 编写Java代码实现冒泡排序 ?
正确回答通过率:70.0%
[ 详情 ] 推荐指数: ★★★ 试题难度: 中级 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
package com.ldm.sort;
public class BubbleSort {
public static void main(String[] args) {
//int[] arr= {3, 8, 1, 17, 9, 13};
//给有100个乱序数据的数组插入数据
int[] randomArray = new int[100];
//插入数据当然要遍历啦!!!
for (int i = 0; i < randomArray.length; i++) {
//如果不会使用Math接口的方法,不用担心
//我会在文章的尾部提供JDK8相关的官方接口文档,直接搜索查看就行啦!!!
randomArray[i] = (int)(Math.random()*100); //随机生成0-100的随机数
}
BubbleSortMethod(randomArray);
}
public static void BubbleSortMethod(int[] arr){
System.out.println("排序之前");
//遍历输出数组
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
int temp = 0;
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-1 -i; j++) {
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println("\n"+"排序之后");
//遍历输出数组
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
}
6. 简述快速排序的原理 ?
正确回答通过率:68.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★★ 试题难度: 中级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
快速排序是对冒泡排序的改进:通过一趟排序将要排序的数据分割成独立的两份,其中一份的所有数据都比另外一份的所有数据小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,达到整个数据变成有序序列
需求:
排序前:{6,1,2,7,9,3,4,5,8}
排序后:{1,2,3,4,5,6,7,8,9}
排序原理:
1、首先设定一个分界值,通过分界值将数组分为左右两部分;
2、将大于或等于分界值的数据放到数组邮编,小于分界值的数据放到数组的左边,此时左边部分的元素都小于或等于分界值。而邮编部分各元素都大于或等于分界值;
3、然后,左边和邮编的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分的数据分为左右两部分,同样在左边放置较小值,右边放置较大值。右侧数组数据做类似处理。
4、重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序,当左右量测数据排序完成后,整个数组排序完成
切分原理:(把一个数组切分成两个数组的基本思想)
1、找一个基准值,用两个指针分别指向数组的头部和尾部
2、先从尾部向头部开始搜索一个比基准值小的元素,搜索到即停止,并记录指针的位置;
3、再从头部向尾部开始搜索一个比基准值大的元素,搜索到即停止,并记录指针的位置;
4、交换当前左边指针位置和邮编指针位置的元素;
5、重复2,3,4步骤,直到左边指针的值大于右边指针的值停止
7. 编写Java代码实现快速排序?
正确回答通过率:51.0%
[ 详情 ] 推荐指数: ★★★★ 试题难度: 高难 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
import java.time.Duration;
import java.time.LocalTime;
public class QuickSort {
public static void main(String[] args) {
test1();
// test2();
}
public static void test1() {
// int arr[]= {-9,78,0,23,-567,70};
int len = 12;
int arr[]=new int [len];
for (int i=0;i arr[i]=(int) (Math.random()100);
}
System.out.println("排序前的数组:");
printArr(arr);
quickSort(arr, 0, arr.length-1);
System.out.println("排序后的数组:");
printArr(arr);
}
//若干万数据,测试排序的时间
public static void test2() {
int len=80000;
int arr[]=new int [len];
for (int i=0;i arr[i]=(int) (Math.random()len);
}
LocalTime before=LocalTime.now();
System.out.println("排序前的时间:"+before);
quickSort(arr,0,len-1);
LocalTime after=LocalTime.now();
Duration duration=Duration.between(before, after);
System.out.println("排序后的时间:"+after);
System.out.println("时间差(毫秒):"+duration.toMillis());
}
private static void quickSort(int[] arr, int lo, int hi) {
if(lo>=hi) return ;
int partition=partition(arr,lo,hi);
quickSort(arr,lo,partition-1);
quickSort(arr,partition+1,hi);
}
private static int partition(int[] arr, int lo, int hi) {
//把最左边的元素当作基准值
int key=arr[lo];
int left=lo;
//
int right=hi+1;
while(true) {
//左指针遇到>=key的值,才停下
while(arr[++left] < key) {
if(lefthi) break;
}
//右指针遇到<=key的值,才停下
while(key < arr[--right]) {
if(rightlo) break;
}
if(left>=right) {
//扫描了所有元素,结束循环
break;
} else {
//交换左右指针
swap(arr,left,right);
}
}
//right指向的值一定是小于或等于key值,所以交换key和右指针的值
swap(arr,lo,right);
return right;
}
/
- 交换数组两个元素
- @param arr
- @param i
- @param j
*/
private static void swap(int[] arr, int i, int j) {
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
private static void printArr(int[] arr) {
for (int i : arr) {
System.out.print(i+" ");
}
System.out.println();
}
}
8. 简述归并排序的原理 ?
正确回答通过率:58.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★ 试题难度: 中级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
首先讲讲归并,归并的过程即将两个数组合并为一个数组,其中参与元素有3个:待合并的数组A/B,最终的结果接收数组C;如果要做到在归并后使得结果有序,那我们可以在过程中进行两个元素的大小比较,然后按顺序放入C,这样最终得到的结果C即是有序的了。
举个例子,假设数组A=[22],B=[4],先将元素对比,然后A[0]>B[0],则将C[0]=B[0],此时已经将B的元素放入C中,B已经没有元素了,接下来将A剩下的元素放入C中,得到C=[4,22]。
上述的过程中,A和B都是单个元素的数组,我们可以看作是有序的数组,我们把这种情况放大到多元素的数组中,
比如A=[22,31],B=[4,44],我们对比A[0]和B[0],得到A[0]>B[0],于是将B[0]放入C[0]中,
此时A=[22,31],B=[44],C=[4];
我们再进行第二遍对比,A[0]和B[1],得到A[0] 此时A=[31],B=[44],C=[4,22];
我们进行第三遍对比,A[1]和B[1],得到A[1] 此时AB元素都对比完了,C=[4,22,31,44];
至此,整个归并排序的过程完结,得到最终结果。
但是按照上述的思路,如果A数组中元素的顺序为[31,22],B元素为[4,44]时,我们最后得到的结果却是C=[4,31,22,44],这显然还是无序的。我们观察A的两种情况:[22,31]和[31,22],区别就是前者是有序的,后者是无序的,B=[4,44]也是有序的,所以,我们需要两个有序的数组,才可以通过上述的归并过程合并排序。
我们得到的结论即是:归并排序是需要将两个有序的子序列进行合并。
9. 编写Java代码实现归并排序?
正确回答通过率:36.0%
[ 详情 ] 推荐指数: ★★★ 试题难度: 高难 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
import java.util.Arrays;
public class Demo912_2 {
public static void main(String[] args) {
int[] nums = {-1, 2, -8, -10}; //给定一个数组
int[] after = sortArray(nums); //的带排序后的数组
System.out.println(Arrays.toString(after)); //打印输出得到数组
}
private static int[] sortArray(int[] nums) {
int len = nums.length;
int[] temp = new int[len];
mergeSort(nums,0,len-1,temp);
return nums;
}
/**
- 递归函数对nums[left...right]进行归并排序
- @param nums 原数组
- @param left 左边的索引
- @param right 右边记录索引位置
- @param temp
*/
private static void mergeSort(int[] nums, int left, int right, int[] temp) {
if (left == right){//当拆分到数组当中只要一个值的时候,结束递归
return;
}
int mid = (left+right)/2; //找到下次要拆分的中间值
mergeSort(nums,left,mid,temp);//记录树左边的
mergeSort(nums,mid+1,right,temp);//记录树右边的
//合并两个区间
for (int i = left; i <= right; i++) {
temp[i] = nums[i];
//temp就是辅助列表,新列表的需要排序的值就是从辅助列表中拿到的
}
int i = left; //给辅助数组里面的值标点
int j = mid +1;
for (int k = left; k <= right ; k++) {//k 就为当前要插入的位置
if (i == mid + 1){
nums[k] = temp[j];
j++;
}else if (j == right+1){
nums[k] = temp[i];
i++;
}
else if (temp[i] <= temp[j]){
nums[k] = temp[i];
i++;
}else {
nums[k] = temp[j];
j++;
}
}
}
}
10. 简述直接选择排序的原理 ?
正确回答通过率:54.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★ 试题难度: 中级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
算法定义
直接选择排序是选择排序的一种,是一种简单的排序方法,根据百科的定义,它的基本思想是:第一次从R[0] ~ R[n - 1]中选取最小值,与R[0]交换,第二次从R[1] ~ R[n - 1]中选取最小值,与R[1]交换...第i次从R[i - 1] ~ R[n - 1]中选取最小值,与R[i - 1]交换...第n-1次从R[n - 2] ~ R[n - 1]中选取最小值,与R[n - 2]交换,总共通过n - 1次,得到一个按排序码从小到大排列的有序序列。
算法原理
直接选择排序算法的原理如下:
1、在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
2、再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
3、重复第二步,直到所有元素均排序完毕。
11. 编写Java代码实现直接选择排序?
正确回答通过率:47.0%
[ 详情 ] 推荐指数: ★★★ 试题难度: 高难 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
package 排序类算法;
import java.util.Scanner;
public class 选择排序 {
public static void main (String[] args) {
Scanner sc = new Scanner(System.in) ;
int n=sc.nextInt();//输入需要进行排序的数据的个数
int num[]=new int[n];
for(int i=0;i num[i]=sc.nextInt();
}
selectionSort(num);
//增强for循环输出数组中的所有元素
for(int x:num){
System.out.println(x);
}
}
public static void selectionSort(int num[]) {
int len=num.length;
int index;
for(int i=0;i index=i;
for(int j=i+1;j //一次循环找到后续数组元素中最大(或者最小的)值,将索引交换,在根据索引位置交换数据
if(num[j]>num[index]) {
index=j;
}
}
int temp=num[i];
num[i]=num[index];
num[index]=temp;
}
}
}
12. 简述希尔排序的原理 ?
正确回答通过率:69.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★ 试题难度: 中级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
希尔排序按其设计者希尔(Donald Shell)的名字命名,它是一种基于插入排序的快速排序算法,要了解希尔排序,必须先掌握插入排序的原理与实现。
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作(且步长要小于数组长度)。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
简单例子分析:
待排序数组: {
6, 5, 3, 1, 8, 7, 2, 4, 9, 0
}
第一次步长h=4,
那么数组按照步长可以拆分成4个小数组([0]6的意思是下标[0]的值为6) {
[0]6, [4]8, [8]9
} {
[1]5, [5]7, [9]0
} {
[2]3, [6]2
} {
[3]1, [7]4
}
对这4个小数组分别进行插入排序后,4个小数组变成: {
[0]6, [4]8, [8]9
} {
[1]0, [5]5, [9]7
} {
[2]2, [6]3
} {
[3]1, [7]4
}
合并起来就是: {
6, 0, 2, 1, 8, 5, 3, 4, 9, 7
}
第二次步长h=1,
那么数组按照步长只有1个数组了 {
6, 0, 2, 1, 8, 5, 3, 4, 9, 7
}
对这个数组进行一次插入排序后,最终顺序就成为: {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
}
13. 编写Java代码实现希尔排序 ?
正确回答通过率:45.0%
[ 详情 ] 推荐指数: ★★★★ 试题难度: 高难 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
package totoSort;
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arrays = new int[] {
1,5,2,3,6,9,4,0,1
}
;
//实现增量的变化
for (int gap = arrays.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arrays.length; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
if(arrays[j] > arrays[j + gap]) {
int temp = arrays[j];
arrays[j] = arrays[j + gap];
arrays[j + gap] = temp;
}
}
}
}
System.out.println(Arrays.toString(arrays));
}
}
14. 简述堆排序的原理 ?
正确回答通过率:34.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★ 试题难度: 高难 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
1、堆排序简介
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:
大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
2、堆排序原理
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
下面给出堆排序的基本步骤:
1)将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
2)将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
3)重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
15. 编写Java代码实现堆排序 ?
正确回答通过率:40.0%
[ 详情 ] 推荐指数: ★★★ 试题难度: 高难 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
堆排序的实现分为两个过程:
1)构建初始堆:将给定无序序列构造成一个大顶堆(或小顶堆),即堆顶元素最大(或最小);
2)堆排序:移除位在第一个数据的根节点,并做最后一个元素放到根节点,然后再调整,使其满足堆的特性。
package zhangchao;
import java.util.Comparator;
import java.util.List;
/**
- 堆排序
- @author zhangchao
/
public class HeapSort {
/* - 创建堆
- @param list 要进行排序的列表
- @param comparator 比较用的函数钩子
- @param list中的元素类型
*/
private static void createHeap(List list, Comparator comparator) {
int size = list.size();
// 假设第0个元素已经是堆了,从第1个元素开始加入堆。
for (int i = 1; i < size; i++) {
int newIndex = i;
while (newIndex > 0) {
// int parentIndex = (newIndex - 1) / 2;
int parentIndex = (newIndex - 1) >> 1;
T parent = list.get(parentIndex);
T newNode = list.get(newIndex);
if (comparator.compare(newNode, parent) > 0) {
list.set(parentIndex, newNode);
list.set(newIndex, parent);
newIndex = parentIndex;
} else {
// 小于等于父亲节点,没有上升的需要,不需要再查找上级节点了。
newIndex = -1;
}
}
}
}
/**
- 排序
- @param list 要进行排序的列表
- @param comparator 比较用的函数钩子
- @param list中的元素类型
*/
public static void sort(List list, Comparator comparator) {
if (null == list || list.size() < 2) {
return;
}
createHeap(list, comparator);
int size = list.size();
for (int i = size - 1; i >= 0; i--) {
// 当前节点和堆顶交换位置。
T current = list.get(i);
list.set(i, list.get(0));
list.set(0, current);
// 当前节点放到堆顶后,不断和子节点做比较,以便调整当前节点在堆中的位置。
int currentIndex = 0;
int heapSize = i;
boolean whileFlag = true;
while(whileFlag) {
// int leftIndex = currentIndex * 2 + 1;
// int rightIndex = currentIndex * 2 + 2;
int leftIndex = (currentIndex << 1) + 1;
int rightIndex = (currentIndex << 1) + 2;
if (rightIndex < heapSize) {
T right = list.get(rightIndex);
T left = list.get(leftIndex);
// 找出最大子节点
int maxIndex = rightIndex;
T max = right;
if (comparator.compare(left, right) > 0) {
maxIndex = leftIndex;
max = left;
}
if (comparator.compare(max, current) > 0) {
list.set(maxIndex, current);
list.set(currentIndex, max);
currentIndex = maxIndex;
} else {
whileFlag = false;
}
/*
这段代码被注释掉,是因为这种比较方式会比上一种方式多一到两次比较。
// 右子节点最大
if (comparator.compare(right, left) > 0 && comparator.compare(right, current) > 0) {
list.set(rightIndex, current);
list.set(currentIndex, right);
currentIndex = rightIndex;
}
// 左子节点最大
else if (comparator.compare(left, right) > 0 && comparator.compare(left, current) > 0) {
list.set(leftIndex, current);
list.set(currentIndex, left);
currentIndex = leftIndex;
} else {
whileFlag = false;
}
*/
} else if (leftIndex < heapSize) {
T left = list.get(leftIndex);
if (comparator.compare(left, current) > 0) {
list.set(leftIndex, current);
list.set(currentIndex, left);
currentIndex = leftIndex;
} else {
whileFlag = false;
}
} else {
whileFlag = false;
}
}
} // end for
}
}
16. 简述排序算法怎么选择( 根据场景 )?
正确回答通过率:38.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★★ 试题难度: 高难 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
数据量规模较⼩,考虑直接插⼊或直接选择。当元素分布有序时直接插⼊将⼤⼤减少⽐较和移动记录的 次数,如果不要求稳定性,可以使⽤直接选择,效率略⾼于直接插⼊。
数据量规模中等,选择希尔排序。
数据量规模较⼤,考虑堆排序(元素分布接近正序或逆序)、快速排序(元素分布随机)和归并排序
(稳定性)。
⼀般不使⽤冒泡。
17. 简述各排序算法的优缺点比较 ?
正确回答通过率:51.0%
[ 详情 ] 推荐指数: ★★★★★ 试题难度: 中级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
1 快速排序
当待排序元素的关键字随机分布时,快速排序的平均时间最短。快速排序比堆排序和归并排序要快2到3倍。
快速排序会出现最坏情况。
快速排序是不稳定的。
2 堆排序
不会出现最坏情况。
3 简单插入排序
当待排序序列基本有序时,可以使用简单插入排序。
4 归并排序
归并排序是稳定的,但是需要一个同样大小的存储空间。
归并排序用递归实现,核心过程是将两个已经有序的数组归并成一个大的有序数组,只需要同时遍历比较即可。
18. 请将排序算法按照时间复杂度进行的分类 ?
正确回答通过率:74.0%
[ 详情 ] 推荐指数: ★★★★★ 试题难度: 中级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
1 平方排序
直接插入排序、直接选择排序、冒泡排序
2 线性对数排序
快速排序、堆排序
3 线性排序
桶排序、基数排序
4 稳定排序
排序前后,key相同的元素的相对位置不变,归并排序是稳定排序。当对多个key进行多轮排序时,就用得上稳定排序
19. 解释算法的时间复杂度是什么 ?
正确回答通过率:88.0% [ 图文 ]
[ 详情 ] 推荐指数: ★★★★ 试题难度: 初级 试题类型: 八股文原理 ▸ 写笔记
试题回答参考思路: >>
算法的时间复杂度表示程序运行完成所需的总时间,它通常用大O表示法来表示。
20. 解释二分法检索如何工作?
在二分法检索中,我们先确定数组的中间位置,然后将要查找的值与数组中间位置的值进行比较,若小于数组中间值,则要查找的值应位于该中间值之前,依此类推,不断缩小查找范围,直至得到最终结果。
代码拓展,二分法查找
def BinarySearch(t,x):
t.sort() #对列表进行排序,列表是有序的,是二分法的前提
low = 0;
high = len(t)-1;
while low < high:
mid = (low+high)/2;
if t[mid] low=mid+1;
elif t[mid]>x:
high = mid-1; else :
return mid
return Non
21. 简述什么是斐波那契数列?用代码如何实现?
正确回答通过率:40.0%
[ 详情 ] 推荐指数: ★★★★ 试题难度: 高难 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
斐波那契数列(Fibonacci Sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为"兔子数列",指的是这样一个数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711... 在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用。
斐波那契数列之所以又称黄金分割数列,是因为随着数列项数的增加,前一项与后一项之比越来越逼近黄金分割的数值 0.6180339887...
斐波那契数列指的是这样一个数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711...
斐波那契数列的特征:第三项开始(含第三项)它的值等于前两项之和。
斐波那契数列代码实现示例,如下所示:
public class Lesson7_4 {
public static void main(String[] args) {
// 斐波那契数列
int fibonacciIndex = 7;
int fibonacciResult = fibonacci(fibonacciIndex);
System.out.println("下标(从0开始)" + fibonacciIndex + "的值为:" + fibonacciResult);
}
/**
- 斐波那契数列
- @param index 斐波那契数列的下标(从0开始)
- @return int
*/
private static int fibonacci(int index) {
if (index == 0 || index == 1) {
return index;
} else {
return fibonacci(index - 1) + fibonacci(index - 2);
}
}
}
执行结果如下:
下标(从0开始)7的值为:13
22. 简述什么是堆排序?用代码如何实现?
正确回答通过率:41.0%
[ 详情 ] 推荐指数: ★★★★★ 试题难度: 高难 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
堆排序(Heap Sort)算法是利用堆结构和二叉树的一些特性来完成排序的。 堆结构是一种树结构,准确来说是一个完全二叉树。完全二叉树每个节点应满足以下条件:
如果按照从小到大的顺序排序,要求非叶节点的数据要大于等于,其左、右子节点的数据;
如果按照从大到小的顺序排序,要求非叶节点的数据小于等于,其左、右子节点的数据。
可以看出,堆结构对左、右子节点的大小没有要求,只规定叶节点要和子节点(左、右)的数据满足大小关系。
堆排序算法代码实现,如下所示:
public class Lesson7_4 {
public static void main(String[] args) {
// 堆排序调用
int[] heapNums = {
18, 1, 6, 27, 15
}
;
System.out.println("堆排序前:" + Arrays.toString(heapNums));
heapSort(heapNums, heapNums.length);
System.out.println("堆排序后:" + Arrays.toString(heapNums));
}
/**
- 堆排序
- @param nums 待排序数组
- @param n 堆大小
*/
private static void heapSort(int[] nums, int n) {
int i, j, k, temp;
// 将 nums[0,n-1] 建成大根堆
for (i = n / 2 - 1; i >= 0; i--) {
// 第 i 个节点,有右子树
while (2 * i + 1 < n) {
j = 2 * i + 1;
if ((j + 1) < n) {
// 右左子树小于右子树,则需要比较右子树
if (nums[j] < nums[j + 1]) {
// 序号增加 1,指向右子树
j++;
}
}
if (nums[i] < nums[j]) {
// 交换数据
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
// 堆被破坏,重新调整
i = j;
} else {
// 左右子节点均大,则堆未被破坏,不需要调整
break;
}
}
}
for (i = n - 1; i > 0; i--) {
// 与第 i 个记录交换
temp = nums[0];
nums[0] = nums[i];
nums[i] = temp;
k = 0;
// 第 i 个节点有右子树
while (2 * k + 1 < i) {
j = 2 * k + 1;
if ((j + 1) < i) {
// 右左子树小于右子树,则需要比较右子树
if (nums[j] < nums[j + 1]) {
// 序号增加 1,指向右子树
j++;
}
}
if (nums[k] < nums[j]) {
// 交换数据
temp = nums[k];
nums[k] = nums[j];
nums[j] = temp;
// 堆被破坏,重新调整
k = j;
} else {
// 左右子节点均大,则堆未被破坏,不需要调整
break;
}
}
// 输出每步排序结果
System.out.print("第" + (n - i) + "次排序:");
System.out.println(Arrays.toString(nums));
}
}
}
执行结果如下:
堆排序前:[18, 1, 6, 27, 15]
第1次排序:[18, 15, 6, 1, 27]
第2次排序:[15, 1, 6, 18, 27]
第3次排序:[6, 1, 15, 18, 27]
第4次排序:[1, 6, 15, 18, 27]
堆排序后:[1, 6, 15, 18, 27]
23. 简述如何实现最长连续不重复子序列 ?
给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
输入:第一行包整数 n,第二行包含n个整数(均在 0∼100000范围内),表示整数序列。
输出:最长的不包含重复的数的连续区间的长度。
正确回答通过率:32.0%
[ 详情 ] 推荐指数: ★★★★ 试题难度: 高难 试题类型: 编程题 ▸ 写笔记
试题回答参考思路: >>
思路:双指针。对于每一个 i,(j,i)表示以 q[i] 结尾的最长连续不重复序列,长度为 i-j+1。由(j,i)已经是不重复序列,因此(j,i+1)要么是不重复序列,要么重复的元素是 q[i+1]。重复的元素是q[i+1]时,只需要找到(j,i)中与 q[i+1] 相等的元素的下标k,就可以更新双指针为(k+1,i+1)。用另一个数组s储存在当前区间(j,i)内每个元素出现的次数,当 s[q[i+1]]>1 时说明(j,i+1)中有重复的数,此时前进 j 指针寻找重复元素。
时间复杂度:O(n)。
import java.util.Scanner;
import java.lang.Math;
class Main
{
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
int n=scanner.nextInt();
int[] q=new int[n];
int[] s=new int[100001];
int r=0;
for(int i=0;i q[i]=scanner.nextInt();
}
for(int i=0,j=0;i s[q[i]]++;
while(s[q[i]]>1){
s[q[j++]]--;
}
r=Math.max(r,i-j+1);
}
System.out.print®;
}
}
24. 如何判断一棵二叉树是否是对称的 ?
请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的
如果一棵二叉树的镜像是其本身,则说明这是一棵对称二叉树
故:
如果root 为空,则直接返回true
如果root 不为空,则需要判断:
(1) root1.left ?= root2.right
(2) root2.left ?= root1.right
这里root1和root2都是root,因为要判断root与root是否镜像
code:
public class solution{
boolean isSymmetrical(TreeNode pRoot) {
if(pRoot == null){
return true;
}
return isMirror(pRoot,pRoot);
}
// 辅助函数,判断两棵树是否为镜像
boolean isMirror(TreeNode n1,TreeNode n2){
// 递归终止条件:
//如果遍历到n1和n2都为null还没有返回false,则说明它俩确实是镜像
if(n1null && n2null) {return true;}
// 如果n1和n2中存在一个等于null而另一个不为null,则返回false
if(n1 == null || n2==null) {return false;}
//如果n1、n2都不为null,但是它俩的value不相等,也返回false
if(n1.val != n2.val) {return false;}
// 开始递归
return isMirror(n1.left, n2.right) && isMirror(n1.right,n2,left);
}
}。