1、基于链表实现的LRU(Least Recently Used 最近最少使用失效原则)缓存
1 public class Mycache {
2 private int count = 0;
3 private Node head = null;
4
5 class Node {
6 private String key;
7 private int value;
8 private Node next = null;
9
10 public Node(String key, int value, Node next) {
11 this.key = key;
12 this.value = value;
13 this.next = next;
14 }
15 public String getKey() {
16 return key;
17 }
18 public void setKey(String key) {
19 this.key = key;
20 }
21 public int getValue() {
22 return value;
23 }
24 public void setValue(int value) {
25 this.value = value;
26 }
27 public Node getNext() {
28 return next;
29 }
30 public void setNext(Node next) {
31 this.next = next;
32 }
33 }
34
35 public void save(String key, int value) {
36 if(head != null) {
37 Node item = head;
38 do {
39 if(item.getKey().equals(key)) {
40 item.setValue(value);
41 return;
42 }
43 item = item.next;
44 }while(item != null);
45
46 if(count < 5) {
47 item = head;
48 head = new Node(key, value, null);
49 head.next = item;
50 count++;
51 }else {
52 System.out.println("基于LRU缓存策略移除队尾元素");
53
54 Node itemToRemove = head;
55 while(itemToRemove.next != null) {
56 itemToRemove = itemToRemove.next;
57 }
58
59 item = head;
60 while(item.next != itemToRemove) {
61 item = item.next;
62 }
63 item.next = null;
64
65 item = head;
66 head = new Node(key, value, null);
67 head.next = item;
68 }
69 }else {
70 head = new Node(key, value, null);
71 count++;
72 }
73 }
74 public int get(String key) {
75 int result = 0;
76 Node itemToRemove = head;
77 do {
78 if(itemToRemove.getKey().equals(key)) {
79 result = itemToRemove.getValue();
80
81 Node item = head;
82 while(item.next != itemToRemove) {
83 item = item.next;
84 }
85 item.next = itemToRemove.next;
86
87 itemToRemove.next = head;
88 head = itemToRemove;
89
90 return result;
91 }
92 itemToRemove = itemToRemove.next;
93 }while(itemToRemove != null);
94
95 throw new RuntimeException("缓存中没有对应的数据");
96 }
97
98 public void iterate() {
99 Node item = head;
100 while(item != null) {
101 System.out.println("【key=" + item.getKey() + ",value=" + item.getValue() + "】");
102 item = item.next;
103 }
104 }
105 public static void main(String[] args) {
106 Mycache cache = new Mycache();
107 cache.save("a", 1);
108 cache.iterate();
109 System.out.println("----------------");
110 cache.save("b", 2);
111 cache.iterate();
112 System.out.println("----------------");
113 cache.save("c", 3);
114 cache.iterate();
115 System.out.println("----------------");
116 cache.save("d", 4);
117 cache.iterate();
118 System.out.println("----------------");
119 cache.save("e", 5);
120 cache.iterate();
121 System.out.println("----------------");
122 cache.save("f", 6);
123 cache.iterate();
124 System.out.println("----------------");
125 int result = cache.get("b");
126 System.out.println(result);
127 cache.iterate();
128 }
129 }
2、基于数组实现的顺序栈
//基于数组实现的顺序栈
public class ArrayStack {
private int[] items;//数组
private int n;//栈的大小
private int count;//栈中元素个数
public ArrayStack(int n) {
items = new int[n];
this.n = n;
this.count = 0;
}
//入栈操作
public boolean push(int value) {
//数组空间不足,直接返回false,入栈失败
if(count >= n) {
return false;
}
//将item放到下标为count的位置,并且count自增1
items[count++] = value;
return true;
}
//出栈操作
public int pop() {
//栈为空,则直接返回null
if(count <= 0) {
return -9999;
}
//返回下标为count-1的数组元素,并且栈中元素个数count自减1
return items[--count];
}
public static void main(String[] args) {
ArrayStack stack = new ArrayStack(3);
stack.push(11);
stack.push(22);
stack.push(33);
stack.push(44);
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
stack.push(555);
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
3、基于链表实现的链式栈
//基于链表实现的链式栈
public class LinkedListStack {
//哨兵机制,带头节点
private Node head = new Node(null);
//入栈操作
public void push(String value) {
if(value == null) {
return;
}
Node newNode = new Node(value);
newNode.next = head.next;
head.next = newNode;
}
//出栈操作
public String pop() {
Node result = head.next;
if(result == null) {
return null;
}
head.next = result.next;
return result.value;
}
class Node{
private String value;
private Node next = null;
public Node(String value) {
this.value = value;
}
}
public static void main(String[] args) {
LinkedListStack stack = new LinkedListStack();
stack.push("aa");
stack.push("bb");
stack.push("cc");
System.out.println(stack.pop());
System.out.println(stack.pop());
stack.push("1111");
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
4、使用两个栈实现的加减乘除四则混合运算的编译器
public class Expression {
//操作数栈
private ArrayStack operandStack = new ArrayStack(20);
//运算符栈
private LinkedListStack operatorStack = new LinkedListStack();
public int process(String expression) {
int result = 0;
String exp = expression;
int firstOperatorIndex = 9999;
do {
firstOperatorIndex = getFirstOperatorIndex(exp);
if(firstOperatorIndex == 9999) {
break;
}
//操作数入栈
operandStack.push(Integer.parseInt(exp.substring(0, firstOperatorIndex)));
//运算符入栈
String topOperator = operatorStack.pop();
String currOperator = exp.substring(firstOperatorIndex, firstOperatorIndex+1);
boolean priorityCompare = true;
while(!(priorityCompare = priorityCompare(currOperator, topOperator))) {
int operand1 = operandStack.pop();
int operand2 = operandStack.pop();
int tmpResult = cal(operand1, operand2, topOperator);
operandStack.push(tmpResult);
topOperator = operatorStack.pop();
}
operatorStack.push(topOperator);
operatorStack.push(currOperator);
exp = exp.substring(firstOperatorIndex + 1);
}while(!exp.isEmpty());
operandStack.push(Integer.parseInt(exp));
String operand = null;
while((operand = operatorStack.pop()) != null) {
int operand1 = operandStack.pop();
int operand2 = operandStack.pop();
int tmpResult = cal(operand1, operand2, operand);
operandStack.push(tmpResult);
}
return operandStack.pop();
}
private int getFirstOperatorIndex(String expression) {
int addIndex = expression.indexOf("+");
int minusIndex = expression.indexOf("-");
int mulIndex = expression.indexOf("*");
int divIndex = expression.indexOf("/");
int firstOperatorIndex = 9999;
if(addIndex > 0) {
firstOperatorIndex = Math.min(firstOperatorIndex, addIndex);
}
if(minusIndex > 0) {
firstOperatorIndex = Math.min(firstOperatorIndex, minusIndex);
}
if(mulIndex > 0) {
firstOperatorIndex = Math.min(firstOperatorIndex, mulIndex);
}
if(divIndex > 0) {
firstOperatorIndex = Math.min(firstOperatorIndex, divIndex);
}
return firstOperatorIndex;
}
//如果source优先级比target高,则返回true,否则返回false
private boolean priorityCompare(String source, String target) {
if(target == null) {
return true;
}
if((source.equals("*") || source.equals("/")) && (target.equals("+") || target.equals("-"))) {
return true;
}
return false;
}
//运算
private int cal(int operand1, int operand2, String operator) {
int result = 0;
if(operator.equals("+")) {
result = operand2 + operand1;
}else if(operator.equals("-")) {
result = operand2 - operand1;
}else if(operator.equals("*")) {
result = operand2 * operand1;
}else if(operator.equals("/")) {
result = operand2 / operand1;
}
return result;
}
public static void main(String[] args) {
Expression expression = new Expression();
System.out.println(expression.process("2+5*4-8/2-1+3*2"));
}
}
5、二分查找
/*
* 问题:假设我们有1000万个整数数据,每个数据占8个字节,如何设计数据结构和算法,快速判断某个整数是否出现在这1000万数据中?
* 分析:1000万个整数数据,每个数据占8个字节,存储在数组中,内存占用差不多是80MB,采用二分查找时间复杂度为O(logn),并且
* 二分查找除了数据本身之外,不需要额外存储其他信息,符合内存的限制。我们说,二分查找是最省内存空间的快速查找算法。
*/
/**
* 二分查找算法:针对的是一个有序的数据集合,时间复杂度为O(logn)
* @author Administrator
*
* 二分查找应用场景的局限性
* 1、二分查找只能用在数据是通过顺序表来存储的数据结构上,简单点说就是二分查找只适合用于数组,因为二分查找算法
* 需要按照下标随机访问元素
* 2、二分查找针对的是有序数据,只适合用在插入、删除操作不频繁,一次排序多次查找的场景中,不适用于动态变化的数据集合
* 3、数据量太大不适合二分查找,原因是二分查找的底层依赖数组这种数据结构,而数组为了支持随机访问的特性,要求使用
* 连续的内存空间,太大量的数据不适合用连续的内存空间存储
*/
public class BinarySearch {
/**
* 最简单情况(有序数组中不存在重复元素) 用循环实现
* @param a 给定的有序数组
* @param value 待查找的目标值
* @return 查找结果的下标
*/
public int simpleSearchBaseLoop(int[] a, int value) {
//当前查找的区间范围
int low = 0, high = a.length - 1;
//中间位置
int mid = 0;
//终止条件(1、区间缩小为0(low>high) 2、 找到目标值)
while(low <= high) {
//计算当前查找区间范围的中间位置
mid = (low + high)/2;
//当前查找区间范围的中间位置的值与目标值进行比较
if(a[mid] == value) {
return mid;
}else if(a[mid] < value) {
low = mid + 1;
}else {
high = mid - 1;
}
}
return -1;
}
/**
* 需要注意的3个地方:
* 1、循环执行条件是 low <= high,而不是low < high
* 2、mid的取值 mid=(low+high)/2 这种写法实际上是有问题的,因为如果low和high比较大的话,两者之和就有可能会溢出。
* 改进的方法是将 mid 的计算方式写成 mid=low+(high-low)/2。更进一步,如果要将性能优化到极致的话,我们可以将这里
* 的除以2操作转化成位运算 mid=low+((high-low)>>1),因为相比除法来说,计算机处理位运算要快得多
* 3、low和high的更新是 low=mid+1,high=mid-1,如果直接写成low=mid,high=mid 就有可能会发生死循环,比如
* 当high=3,low=3,并且a[3]不等于value时,就会导致一直循环不退出
*/
/**
* 最简单情况(有序数组中不存在重复元素) 用递归实现
* @param a 给定的有序数组
* @param low 当前查找范围的最小值
* @param high 当前查找范围的最大值
* @param value 待查找的目标值
* @return 查找结果的下标
*/
public int simpleSearchBaseRecursion(int[] a, int low, int high, int value) {
//判断当前查找范围是否已经缩小为0
if(low > high) {
return -1;
}
int mid = low + ((high-low)>>1);
if(a[mid] == value) {
//找到目标值直接返回
return mid;
}else if(a[mid] < value) {
//未找到目标值,缩小范围递归查找
return simpleSearchBaseRecursion(a, mid+1, high, value);
}else {
//未找到目标值,缩小范围递归查找
return simpleSearchBaseRecursion(a, low, mid-1, value);
}
}
/**
* 二分查找变种1:查找第一个值等于给定值的元素
* @param a 给定的有序数组
* @param value 待查找的目标值
* @return 查找结果的下标
*/
public int binarySearchVarietas1(int[] a, int value) {
/*************简洁写法*********************
int n = a.length;
int low = 0, high = n - 1;
int mid = 0;
while(low <= high) {
mid = low + ((high - low)>>1);
if(a[mid] < value) {
low = mid + 1;
}else {
high = mid - 1;
}
}
//如果low<n,则说明value在[a[0], a[n-1]]范围内,此时只需要判断a[low]是否等于value即可
if(low < n && a[low] == value) {
return low;
}else {
return -1;
}
************************************/
int n = a.length;
int low = 0, high = n - 1;
int mid = 0;
while(low <= high) {
mid = low + ((high - low)>>1);
if(a[mid] < value) {
low = mid + 1;
}else if(a[mid] > value) {
high = mid - 1;
}else {
//判断是否是第一个等于value的元素
if(mid == 0 || a[mid-1] != value) {
return mid;
}
high = mid - 1;
}
}
return -1;
}
/**
* 二分查找变种2:查找最后一个值等于给定值的元素
* @param a 给定的有序数组
* @param value 待查找的目标值
* @return 查找结果的下标
*/
public int binarySearchVarietas2(int[] a, int value) {
int n = a.length;
int low = 0, high = n - 1;
int mid = 0;
while(low <= high) {
mid = low + ((high - low)>>1);
if(a[mid] < value) {
low = mid + 1;
}else if(a[mid] > value) {
high = mid - 1;
}else {
//判断是否是最后一个等于value的元素
if(mid == n-1 || a[mid+1] != value) {
return mid;
}
low = mid + 1;
}
}
return -1;
}
/**
* 二分查找变种3:查找第一个大于等于给定值的元素
* @param a 给定的有序数组
* @param value 待查找的目标值
* @return 查找结果的下标
*/
public int binarySearchVarietas3(int[] a, int value) {
int n = a.length;
int low = 0, high = n - 1;
int mid = 0;
while(low <= high) {
mid = low + ((high - low)>>1);
if(a[mid] < value) {
low = mid + 1;
}else {
//判断是否是第一个小于等于value的元素
if(mid == 0 || a[mid-1] < value) {
return mid;
}
high = mid - 1;
}
}
return -1;
}
/**
* 二分查找变种4:查找最后一个小于等于给定值的元素
* @param a 给定的有序数组
* @param value 待查找的目标值
* @return 查找结果的下标
*/
public int binarySearchVarietas4(int[] a, int value) {
int n = a.length;
int low = 0, high = n - 1;
int mid = 0;
while(low <= high) {
mid = low + ((high - low)>>1);
if(a[mid] > value) {
high = mid - 1;
}else {
//判断是否是最后一个等于value的元素
if(mid == n-1 || a[mid+1] > value) {
return mid;
}
low = mid + 1;
}
}
return -1;
}
}