面试题
单向链表:实现单向链表元素的反转
- 先定义一个新节点reverseHead = new HeroHead()
- 从头到尾遍历原来的元素,没遍历一个节点,将其取出,并放到新的链表reverseHead()的最前端
- 原来链表的head.next = reverseHead
- 只需要一个辅助节点
注意:先指针下移,再复制元素
public static HeroNode reverse(HeroNode head) {
//TODO 如果当前链表为空,或
HeroNode reverseHead = new HeroNode(0,"","");
HeroNode next = head.next;
while (true) {
if (next == null) {
break;
}
HeroNode node = next;
//next先指针下移,再复制元素
next = next.next;
node.next = reverseHead.next;
reverseHead.next = node;
}
head.next = reverseHead.next;
return head;
}
单向链表与双向链表的使用区别
添加:单向链表添加,指针找到添加元素的前一个节点,双向链表指针找到当前节点
双向链表
-双向链表的操作,temp都是指向当前节点
添加:先找到双向链表的最后一个节点
temp.next = newHeroNode
newHeroNode.pre = temp
删除:- 删除节点要注意是否是最后一个节点!!!
temp.next=temp.next.next;
temp.next.pre = temp.pre
修改:对于链表的修改,需要找到指定的元素,所以可以定义一个flag
栈
可以用数组实现栈,也可以用链表实现栈
- 使用
数组保存栈的元素 - 初始化top = -1
- 入栈:
top++; stack[top] = value - 出栈:
int value = stack[top]; top--; return value
栈满,栈空
入栈,出栈
使用栈实现计算器
public class Calculator {
public static void main(String[] args) {
String expression = "3+2*6-2";
ArrayStack2 numStack = new ArrayStack2(10);
ArrayStack2 operStack = new ArrayStack2(20);
//定义需要的相关变量
int index = 0;
int num1 = 0;
int num2 = 0;
int oper = 0;
int res = 0;
char ch = ' ';//将每次扫描的char保存到ch
//while循环遍历expression
while (true) {
ch = expression.substring(index,index+1).charAt(0);
if (operStack.isOper(ch)) {
if (operStack.isEmpty()) {
operStack.push(ch);
}else {
if (operStack.priority(ch) >= operStack.priority(operStack.peek())) {
operStack.push(ch);
}else {
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1,num2,oper);
numStack.push(res);
operStack.push(ch);
}
}
}else {
numStack.push(ch-48);
}
index++;
if (index >= expression.length()) {
break;
}
}
//当出了循环的时候,操作符栈里面的元素都是 + -,高优先级的已经被计算过了
while (true) {
if (operStack.isEmpty()) {
break;
}
num1 = numStack.pop();
num2 = numStack.pop();
oper = operStack.pop();
res = numStack.cal(num1, num2, oper);
numStack.push(res);
}
int res2 = numStack.pop();
System.out.println("表达式" + expression + "="+res2);
}
}
class ArrayStack2{
private int maxSize;
private int[] stack;
private int top = -1;
public int getMaxSize() {
return maxSize;
}
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
public int[] getStack() {
return stack;
}
public void setStack(int[] stack) {
this.stack = stack;
}
public int getTop() {
return top;
}
public void setTop(int top) {
this.top = top;
}
public ArrayStack2(int maxSize) {
this.maxSize = maxSize;
stack = new int[this.maxSize];
}
//栈满
public boolean isFull() {
return top == maxSize -1;
}
public int peek() {
return stack[top];
}
//栈空
public boolean isEmpty(){
return top == -1;
}
//入栈
public void push(int value) {
if (isFull()) {
System.out.println("栈满");
return;
}
top++;
stack[top] = value;
}
//出栈
public int pop() {
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据");
}
int value = stack[top];
top--;
return value;
}
//遍历栈
public void list() {
while (!isEmpty()) {
System.out.println("stack[" + top + "]" +"=" +stack[top]);
top--;
}
}
public void list1() {
if (isEmpty()) {
System.out.println("栈空,没有数据~");
return;
}
for (int i = top; i >=0 ; i--) {
System.out.print("stack[" + i+"]" + "="+stack[i]);
}
}
//判断是不是一个运算符
public boolean isOper(char val) {
return val == '+' || val == '-' || val == '*' || val == '/';
}
//返回运算符的优先级
public int priority(int oper) {
if (oper == '*' || oper == '/') {
return 1;
}else if (oper == '+' || oper == '-') {
return 0;
}else {
return -1;
}
}
//计算方法
public int cal(int num1,int num2,int oper) {
int result = 0;
switch (oper) {
case '+':
result = num1 + num2;
break;
case '-':
result = num2 - num1;
break;
case '*':
result = num2 * num1;
break;
case '/':
result = num2 / num1;
break;
default:
break;
}
return result;
}
}
问题:当输入为70的时候,不能辨别为两个数字
不能在扫描是数字的时候就直接入栈需要再向后面扫描一位,直到不是数字时,再进行拼接入栈
排序算法
冒泡排序
一次比较相邻的两个元素,并交换每个大循环,会排除一个顺序优化:当有一个大循环没有发生交换时,代表已经有序,break,退出后面的其他大循环- 一个冒泡排序最少执行
元素-1次,还是在全是相同的情况下
优化的冒泡排序
int[] a = new int[]{1,1,1,1,1,1,1,1,1};
boolean flag = false;
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - i - 1; j++) {
if (a[j] > a[j+1]) {
flag = true;
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
if (!flag) {
break;
}else {
//TODO 在一次大排序中可能交换过,flag = true
//TODO 所以需要重置flag = false
flag = false;
}
}
选择排序
- 第一轮将最小的元素放在第一位
- 第二轮将其他最小的放在第二位
- 每次只交换两个位置
int[] a = new int[]{101,34,43,32,1,65,21,119,1};
//101 34 119 1
//1 34 119 101
int index = 0;
int min = 0;
for (int i = 0; i < a.length; i++) {
index = i;
min = a[i];
for (int j = i+1; j < a.length ; j++) {
//TODO 这里不像冒泡排序,没有往后看一位,且是i开头,不需要a.length-i
//TODO 且本身就不会越界
if (min > a[j]) {
min = a[j];
index = j;
}
}
a[index] = a[i];
a[i] = min;
}
插入排序
- 将数据分成两组,从后往前遍历,比它小则后移,比他大则定位
//{101,34,52,1} ==> {34,101,1,12} ==> {1,34,101,12}
int[] arr = new int[]{34,101,1,12,543,13,53,31,34,31,4234};
for (int i=1;i<arr.length;i++) {
int insertVal = arr[i]; //1
int insertIndex = i - 1;//1
while (insertIndex >= 0 && insertVal < arr[insertIndex]) { //index=0 1 < a[0]
arr[insertIndex + 1] = arr[insertIndex]; // a[1] = a[0] = 34
insertIndex--;//index--=0-1=-1;结束了 //1-1=0; //34,101,101 //0-1=-1 34,34,101
}
arr[insertIndex + 1] = insertVal; //a[0] = 1;
}
System.out.println(Arrays.toString(arr));
希尔排序
int[] a = new int[]{8,9,1,7,2,3,5,4,6,0};
int temp = 0;
for (int gap = a.length/2;gap > 0 ;gap/= 2) {
for (int i = gap; i < a.length; i++) {
for (int j = i - gap; j >= 0; j -= gap) { //i=7 j=7-5=2
if (a[j] > a[j + gap]) {
temp = a[j];
a[j] = a[j + gap];
a[j + gap] = temp;
}
}
}
}
线性查找
就是遍历数组元素,最基本的查找
public static int search(int[] a,int num) {
boolean flag = false;
for (int i = 0; i < a.length; i++) {
if (a[i] == num) {
flag = true;
System.out.println("找到了,下标为"+ i);
return i;
}
if (i == a.length -1) {
System.out.println("找不到");
return -1;
}
}
return -1;
}
二分查找
二分查找是查找算法,需要传入一个需要查找的数
int mid = (left + right) /2二分查找的前提是:数组元素是有序的递归调用:要知道什么时候结束递归- 退出递归的条件,找到了如何退出,找不到如何退出
定义flag变量,找到更改,找不到不更改,最后根据是否更改flag,判断是否找到该元素
public static void binarySearch(int[] a,int num) {
int left=0;
int right = a.length-1;
boolean flag = true;
while (left <= right) {
int middle = (left + right) / 2;
if (num == a[middle]) {
System.out.println("找到了,位置为" + middle);
flag = false;
break;
}else if (a[middle] > num) {
right = middle - 1;
}else {
left = middle + 1;
}
}
if (flag) {
System.out.println("找不到");
}
}