面试总结

  1. 排序算法的稳定性
    在这里插入图片描述
顺便将排序算法的时间复杂度也进行分析

 - 稳定性的概念:在待排序的记录序列中,存在多个具有相同的关键字记录以后,即类似ri = rj这种相邻的不变,在排序以后的相对次序也不发生改变,则称这种算法是稳定的
 
不稳定稳定的排序算法:堆排序、快速排序、希尔排序、直接选择排序、桶排序是不稳定的
稳定的排序算法:基数排序、冒泡排序、插入排序、折半插入排序、归并排序

冒泡排序,对比相邻元素之间的大小,O(n2)
稳定,因为在变换的时候不会改变相邻之间的相对次序
func BubbleSort(arr []int) []int {
	nLen := len(arr)
	for i := 0; i < nLen; i++ {
		for j := i + 1; j < nLen; j++ {
			if arr[j+1] < arr[j] {
				arr[j+1], arr[j] = arr[j], arr[j+1]
			}
		}
	}
	return arr
}

选择排序,每次选出最小的值,如果值小于最小数,则将其放在最前面 O(n2)
不稳定,因为每次取出来一位以后就会改变相对位置

func SelectSort(arr []int) []int {
	nLen := len(arr)
	for i := 0; i < nLen; i++ {
		min := i // 记录每次的最小值
		for j := i + 1; j < nLen; j++ {
			if arr[j] < arr[min] {
				min = j
			}
		}
		arr[i], arr[min] = arr[min], arr[i]
	}
	return arr
}


// 插入排序,将没有排序好的值插到前面以后排好顺序的值里头
// 插入排序由于是从后往前插入的,所以不会改变相对位置 所以是稳定的
// 二分插入法,基于之前都是排序好的list,使用二分法插入
func InsertSort(arr []int) []int {
	nLen := len(arr)
	for i := 1; i < nLen; i++ {
		for j := i; j > 0; j-- {
			// 如果小于旁边的值,则交换相对位置
			if arr[j-1] > arr[j] {
				arr[j], arr[j-1] = arr[j-1], arr[j]
			} else {
				break
			}
		}
	}
	return arr
}

// 归并排序,归并排序的时间复杂度O(nlogn) 空间复杂度是O(n)
// 稳定

func Merge(arr []int) []int {
	nLen := len(arr)
	if nLen < 2 {
		return arr
	}
	mid := nLen / 2
	leftArr := Merge(arr[:mid])
	rightArr := Merge(arr[mid:])
	res := MergeSort(leftArr, rightArr)
	return res
}

func MergeSort(leftArr []int, rightArr []int) []int {
	arrNew := []int{}
	var i, j int
	for i < len(leftArr) && j < len(rightArr) {
		if leftArr[i] < rightArr[j] {
			arrNew = append(arrNew, leftArr[i])
			i += 1
		} else {
			arrNew = append(arrNew, rightArr[j])
			j += 1
		}
	}
	arrNew = append(arrNew, leftArr[i:]...)
	arrNew = append(arrNew, rightArr[j:]...)
	return arrNew
}

// 单路快排,时间复杂度O(nlogn), 最差时间复杂度是O(n2)
// 快排是不稳定的,受到原来数组的顺序影响,若原来的数组就是就有序,则会将数据全分到一遍,最后导致变成冒泡排序
// 单路快排没有考虑数据与基准值相等的情况,容易一边大一边小
// 双路快排对于相等的值就是不交换,多路快排则针对相等的值单独提取

func QSortRecursion(arr []int){
	if len(arr) <2{
		return
	}

	head, tail := 0, len(arr) -1
	randomNum := getRandNum(len(arr)-1)
	arr[0], arr[randomNum] = arr[randomNum], arr[0]
	poivt := arr[0]

	for i := 1; i<=tail; {
		if arr[i] <= poivt {
			arr[i], arr[head] = arr[head], arr[i]
			head ++
			i ++
		} else {
			arr[i], arr[tail] = arr[tail], arr[i]
			tail --
		}
	}
	QSortRecursion(arr[:head])
	QSortRecursion(arr[head+1:])
}

func getRandNum(num int) int{
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(num)
}


  1. redis是单线程还是多线程的,怎么证明
  2. 搜索算法有哪些
顺序查找法:即顺序遍历,时间复杂度是O(n)
二分查找法:折半查找,每次mid:=1/2进行比较,时间复杂度是O(logn)
插值查找法:针对数字的特殊性进行查找,比如在0~10000中查找5,在二分法的基础上进行查找,将公式改进为mid=low+(key-a[low])/(a[high]-a[low])*(high-low),时间复杂度是O(logn),数据均匀比较好查找
斐波那契查找法:它也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率,时间复杂度是O(logn)
  1. Top k算法,大堆顶和小堆顶
从亿万数据从取出前100的数字,维护一个堆栈实现
大顶堆:每个结点的值都大于或等于其左右孩子结点的值
小顶堆:每个结点的值都小于或等于其左右孩子结点的值
  1. 如果发现SQL很慢怎么查询索引有没有覆盖
在这里插入代码片
  1. 加密算法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值