• 数据结构与算法无用随笔


    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;
        }
    }
  • 相关阅读:
    Git ignore file for Xcode projects
    How can I create a zip archive of a whole directory via terminal without hidden files?
    What is a bare git repository?
    How to tell if UIViewController's view is visible
    Adding A Shadow To UIView
    Properties
    iOS中nil,Nil,NULL之间的区别
    FMDB的简单使用
    iOS 加载图片选择imageNamed 方法还是 imageWithContentsOfFile?
    对retain 和 assign的理解
  • 原文地址:https://www.cnblogs.com/jiangwangxiang/p/10754747.html
Copyright © 2020-2023  润新知