一 数据结构
1.你熟悉什么数据结构?
数组 链表
栈 队列 哈希
二叉树 二叉查找树 二叉堆
b树 b+树
2.b树 b+树 b*树
b和b+都是节点可以有很多子节点,区别是b树所有的节点都可以存储关键字,而b+树只有叶子节点存储关键字,适用于数据库索引。
3.树的中序遍历
4.二叉平衡树,怎么用一维数组存储
使用数组存储时,会按照层级顺序把二叉树的节点放到数组中对应的位置上。如果某一个节点的左孩子或者右孩子空缺,则数据的相应位置也空出来。
设计思路:
假设一个父节点的下标是p
左孩子下标=2p +1
右孩子下标=2p+2反过来,左孩子的下标是l,它父节点下标为:(l - 1)/2
二 算法
1.快排?快排的实现过程?复杂度如何?简单代码实现?
方式:
双边循环法(代码实现复杂)
单边循环法(推荐)
复杂度:
nlogn
单边循环法实现过程
1-先找到一个基准元素,起始下标
2-遍历,如果元素比基准元素小,下标+1
此元素与下标对应元素交换位置
3-当遍历完后,基准元素与当前下标元素交换位置,此时基准元素就分成了两组数据
4-两边的数据在递归调用,分而治之,直到起始下标和终止下标结束,则不能在拆分
5-遍历数组元素即可
单边循环法代码实现:
public static void quickSort(int[] arr, int startIndex, int endIndex)
{
// 递归结束条件:startIndex大于或等于endIndex时
if (startIndex >= endIndex) {
return;
}
// 得到基准元素位置
int pivotIndex = partition(arr, startIndex, endIndex);
// 根据基准元素,分成两部分进行递归排序
quickSort(arr, startIndex, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, endIndex);
}
/**
* 分治(单边循环法)
* @param arr 待交换的数组
* @param startIndex 起始下标
* @param endIndex 结束下标
*/
private static int partition(int[] arr, int startIndex, int endIndex) {
// 取第1个位置(也可以选择随机位置)的元素作为基准元素
int pivot = arr[startIndex];
int mark = startIndex;
for(int i=startIndex+1; i<=endIndex; i++){
if(arr[i]<pivot){
mark ++;
int p = arr[mark];
arr[mark] = arr[i];
arr[i] = p;
}
}
arr[startIndex] = arr[mark];
arr[mark] = pivot;
return mark;
}
public static void main(String[] args) {
int[] arr = new int[] {4,4,6,5,3,2,8,1};
quickSort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
说明:
递归代码的书写特点,先找到一个循环的代码,在找出跳出循环的条件,递归的调用循环代码。
2.二分查找原理,简单的一个代码
算法思想:
设置开始位置start,结束位置end,以及中间位置 mid=(end+start)/2,
如果arr[index]=mid,返回mid
如果arr[index]>mid,从后半段查找,将start设置为mid+1
如果arr[index]<mid,从后半段查找,将end设置为mid-1
如果start>end,返回-1,说明所查元素不存在
代码:
public class Select1_SuanFa2 {
public static void main(String[] args) {
System.out.println(select(44));
}
public static int select(int target) {
//定义数组
int[] arr = {21,32,36,44,45,36,47,38,29};
//定义初始位置
int start = 0;
//定义结束位置
int end = arr.length-1;
//定义中间位置
int mid = (start+end)/2;
while(true) {
//如果没有这个元素,则start>=end,返回-1
if(start>end) {
return -1;
}
//判断是否和中间位置元素值相等
if(arr[mid] == target) {
//将中间位置的索引赋值给目标位置
return mid;
}else {
if(arr[mid] > target) {
//将end位置设置为中间位置减一
end = mid-1;
}else {
//将start位置设置为中间位置加1
start = mid+1;
}
//取出新的中间位置(别忘记了)
mid = (start+end)/2;
}
}
}
}
3.怎么判断链表是否有环?
思路:
两个指针分别按照固定步长行走,P1一次走1布,P2一次走2布,如果链表有环,P1和P2会有相遇的时刻。(追击问题解法)
代码:
/**
* 判断是否有环
* @param head 链表头节点
*/
public static boolean isCycle(Node head) {
Node p1 = head;
Node p2 = head;
while (p2!=null && p2.next!=null){ ;
p1 = p1.next;
p2 = p2.next.next;
if(p1 == p2){
return true;
}
return false;
}
/**
* 链表节点
*/
private static class Node {
int data;
Node next;
Node(int data) {
this.data = data;
}
}
public static void main(String[] args) throws Exception {
Node node1 = new Node(5);
Node node2 = new Node(3);
Node node3 = new Node(7);
Node node4 = new Node(2);
Node node5 = new Node(6);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node2;
System.out.println(isCycle(node1));
}
4.链表的定义,怎么实现链表翻转?
链表翻转代码参考:
5.怎么求数组的最大子序列和
6.栈中最小值
代码如下:
private Stack<Integer> mainStack = new Stack<Integer>();
private Stack<Integer> minStack = new Stack<Integer>();
/**
* 入栈操作
* @param element 入栈的元素
*/
public void push(int element) {
mainStack.push(element);
//如果辅助栈为空,或者新元素小于或等于辅助栈栈顶,则将新元素压入辅助栈
if (minStack.empty() || element <= minStack.peek()) {
minStack.push(element);
}
}
/**
* 出栈操作
*/
public Integer pop() {
//如果出栈元素和辅助栈栈顶元素值相等,辅助栈出栈
if (mainStack.peek().equals(minStack.peek())) {
minStack.pop();
}
return mainStack.pop();
}
/**
* 获取栈的最小元素
*/
public int getMin() throws Exception {
if (mainStack.empty()) {
throw new Exception("stack is empty");
}
return minStack.peek();
}
public static void main(String[] args) throws Exception {
MinStack stack = new MinStack();
stack.push(4);
stack.push(9);
stack.push(7);
stack.push(3);
stack.push(8);
stack.push(5);
System.out.println(stack.getMin());
stack.pop();
stack.pop();
stack.pop();
System.out.println(stack.getMin());
}