数据结构与算法无用随笔
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; } }