數據結構與算法無用隨筆

一、基於鏈表實現的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 }

 二、基於數組實現的順序棧

//基於數組實現的順序棧
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());
    }
}

三、基於鏈表實現的鏈式棧

//基於鏈表實現的鏈式棧
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());
    }
}

四、使用兩個棧實現的加減乘除四則混合運算的編譯器

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"));
    }
}

 五、二分查找

/*
 * 問題:假設咱們有1000萬個整數數據,每一個數據佔8個字節,如何設計數據結構和算法,快速判斷某個整數是否出如今這1000萬數據中?
 * 分析:1000萬個整數數據,每一個數據佔8個字節,存儲在數組中,內存佔用差很少是80MB,採用二分查找時間複雜度爲O(logn),而且
 *     二分查找除了數據自己以外,不須要額外存儲其餘信息,符合內存的限制。咱們說,二分查找是最省內存空間的快速查找算法。
 */

/**
 * 二分查找算法:針對的是一個有序的數據集合,時間複雜度爲O(logn)
 * @author Administrator
 *
 * 二分查找應用場景的侷限性
 *   一、二分查找只能用在數據是經過順序表來存儲的數據結構上,簡單點說就是二分查找只適合用於數組,由於二分查找算法
 *     須要按照下標隨機訪問元素
 *   二、二分查找針對的是有序數據,只適合用在插入、刪除操做不頻繁,一次排序屢次查找的場景中,不適用於動態變化的數據集合
 *   三、數據量太大不適合二分查找,緣由是二分查找的底層依賴數組這種數據結構,而數組爲了支持隨機訪問的特性,要求使用
 *     連續的內存空間,太大量的數據不適合用連續的內存空間存儲
 */
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;
        //終止條件(一、區間縮小爲0(low>high)  二、 找到目標值)
        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個地方:
     *   一、循環執行條件是 low <= high,而不是low < high
     *   二、mid的取值  mid=(low+high)/2 這種寫法其實是有問題的,由於若是low和high比較大的話,二者之和就有可能會溢出。
     *     改進的方法是將 mid 的計算方式寫成 mid=low+(high-low)/2。更進一步,若是要將性能優化到極致的話,咱們能夠將這裏
     *     的除以2操做轉化成位運算 mid=low+((high-low)>>1),由於相比除法來講,計算機處理位運算要快得多
     *   三、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;
    }
}
相關文章
相關標籤/搜索