目錄
1. 棧和隊列
1.用兩個隊列實現(xiàn)棧
2.用兩個棧實現(xiàn)隊列
3.實現(xiàn)一個棧桨啃,可以用常數(shù)級時間找出棧中的最小值
4.判斷棧的壓棧、彈棧序列是否合法
2. 鏈表
1.反轉鏈表(使用遞歸和迭代兩種解法檬输,了解頭插法)
2.刪除鏈表的當前節(jié)點
3.刪除倒數(shù)第 k 個節(jié)點
4.兩個有序鏈表合并
5.判斷鏈表是否有環(huán)
6.兩個鏈表的第一個公共節(jié)點(提示:考慮鏈表有環(huán)的情況)
7.刪除鏈表中重復節(jié)點
3. 樹照瘾、二分
1.一個序列,它的形式是12349678丧慈,9是峰值析命,經(jīng)歷了一個上升又下降的過程,找出里面的最大值的位置O(logN)
2.深度優(yōu)先遍歷二叉樹
3.廣度優(yōu)先遍歷二叉樹
4.前序遍歷二叉樹
5.中序遍歷二叉樹
6.輸入一棵二叉樹的根結點,求該樹的深度
7.根據(jù)中序和后序遍歷結果重建二叉樹
8.根據(jù)中序和前序遍歷結果重建二叉樹
9.翻轉二叉樹
10.判斷某個數(shù)組是不是二叉樹的后序遍歷結果
11.二叉樹中和為某個值的路徑
12.二叉樹中某個節(jié)點的下一個節(jié)點
4. 遞歸、動態(tài)規(guī)劃
1.股票買入賣出的最佳時間
2.遞歸方法求數(shù)組的最大值
3.背包問題
4.連續(xù)子數(shù)組的最大和
5.實現(xiàn)簡單的正則表達式匹配
5.字符串
1.給一串字符串比如abbbcccd鹃愤,輸出a1b3c3d1,O(n)
2.例如輸入字符串”I am a student. ”,則輸出”student. a am I”
3.比如輸入字符串”abcefg”和數(shù)字 2,該函數(shù)將返回左旋轉 2 位得到的結”cdefab”
4.判斷是否是回文字符
5.最長回文子串
6.最長無重復子串
7.字符串轉數(shù)字
8.KMP 算法
9.字符串全排列
10.翻轉字符串
6. 排序
1.歸并排序簇搅、拓展:求數(shù)組中的逆序?qū)€數(shù)
2.快速排序 重點:partion 函數(shù)的實現(xiàn)
3.堆排序
4.數(shù)組元素值域已知時,考慮 基數(shù)排序 和 桶排序
7. 大數(shù)據(jù)
1.海量N個數(shù)中求前M大個數(shù)(選擇第M大數(shù))
8. 數(shù)組软吐、矩陣
1.回形馍资,矩陣
2.蛇形矩陣
3.在排序數(shù)組中查找和為給定值的兩個數(shù)字(思路)
9. 位運算
1.給一個十進制數(shù)字,求它的二進制表示中关噪,有多少個 1 (n &= n - 1)
2.給一個數(shù)組鸟蟹,所有數(shù)字都出現(xiàn)了偶數(shù)次,只有一個出現(xiàn)了一次使兔,找出這個數(shù)
3.給一個數(shù)組建钥,所有數(shù)字都出現(xiàn)了三次,只有一個出現(xiàn)了一次虐沥,找出這個數(shù)
4.給一個數(shù)組熊经,所有數(shù)組都出現(xiàn)了偶數(shù)次,只有兩個數(shù)字出現(xiàn)了一次欲险,找出這兩個數(shù)
10. JAVA相關題
1.生產(chǎn)者/消費者(wait() / notify()方法)
2.生產(chǎn)者/消費者(await() / signal()方法)
3.生產(chǎn)者/消費者(BlockingQueue阻塞隊列方法)
4.觀察者設計模式
---持續(xù)跟新镐依,歡迎糾錯---
---【】數(shù)字越大問題越難---
--- 根據(jù)目錄Ctrl C.V快速定位題解答---
棧和隊列
- 【2】用兩個隊列實現(xiàn)棧
public class TwoQueue { private LinkedList<String> queue1; private LinkedList<String> queue2; public TwoQueue(){ queue1 = new LinkedList<String>(); queue2 = new LinkedList<String>(); } public String pop(){ String re =null; if(queue1.size() == 0 && queue2.size() == 0){ return null; } if(queue2.size() == 0){ while(queue1.size() >0){ re = queue1.removeFirst(); if(queue1.size() != 0){ //最后一個不存進去 queue2.addLast(re); } } }else if(queue1.size() == 0){ while(queue2.size() >0){ re = queue2.removeFirst(); if(queue2.size()!=0){ queue1.addLast(re); } } } return re; } public String push(String str){ if(queue1.size() ==0 && queue2.size() == 0){ queue1.addLast(str); } if(queue1.size()!=0){ queue1.addLast(str); }else if(queue2.size()!=0){ queue2.addLast(str); } return str; }
- 【2】用兩個棧實現(xiàn)隊列
class MList<T> { // 插入棧,只用于插入的數(shù)據(jù) private Stack<T> stack1 = new Stack<T>(); // 彈出棧,只用于彈出數(shù)據(jù) private Stack<T> stack2 = new Stack<T>(); public MList() { } // 添加操作,入隊 public void appendTail(T t) { stack1.add(t); } // 刪除操作,出隊 public T deleteHead() { // 先判斷彈出棧是否為空,如果為空就將插入棧的所有數(shù)據(jù)彈出棧, // 并且將彈出的數(shù)據(jù)壓入彈出棧中 if (stack2.isEmpty()) { while (!stack1.isEmpty()) { stack2.add(stack1.pop()); } } // 如果彈出棧中還沒有數(shù)據(jù)就拋出異常 if (stack2.isEmpty()) { throw new RuntimeException("No more element."); } // 返回彈出棧的棧頂元素,對應的就是隊首元素。 return stack2.pop(); } }
- 【2】實現(xiàn)一個棧天试,可以用常數(shù)級時間找出棧中的最小值
- 【3】判斷棧的壓棧槐壳、彈棧序列是否合法
鏈表
-
【2】反轉鏈表(使用遞歸和迭代兩種解法,了解頭插法)
public static ListNode reverseList(ListNode head) { // 創(chuàng)建一個臨時結點,當作尾插法的邏輯頭結點 ListNode root = new ListNode(); // 邏輯頭結點點的下一個結點為空 root.next = null; // 用于記錄要處理的下一個結點 ListNode next; // 當前處理的結點不為空 while (head != null) { // 記錄要處理的下一個結點 next = head.next; // 當前結點的下一個結點指向邏輯頭結點的下一個結點 head.next = root.next; // 邏輯頭結點的下一個結點指向當前處理的結點 root.next = head; // 上面操作完成了一個結點的頭插 // 當前結點指向下一個要處理的結點 head = next; } // 邏輯頭結點的下一個結點就是返回后的頭結點 return root.next; }
【3】刪除鏈表的當前節(jié)點
-
【3】刪除倒數(shù)第 k 個節(jié)點
public static ListNode findKthToTail(ListNode head, int k) { // 輸入的鏈表不能為空,并且k大于0 if (k < 1 || head == null) { return null; } // 指向頭結點 ListNode pointer = head; // 倒數(shù)第k個結點與倒數(shù)第一個結點相隔k-1個位置 // pointer先走k-1個位置 for (int i = 1; i < k; i++) { // 說明還有結點 if (pointer.next != null) { pointer = pointer.next; } // 已經(jīng)沒有節(jié)點了,但是i還沒有到達k-1說明k太大,鏈表中沒有那么多的元素 else { // 返回結果 return null; } } // pointer還沒有走到鏈表的末尾,那么pointer和head一起走, // 當pointer走到最后一個結點即,pointer.next=null時,head就是倒數(shù)第k個結點 while (pointer.next != null) { head = head.next; pointer = pointer.next; } // 返回結果 return head; }
【1】兩個有序鏈表合并
【2*】判斷鏈表是否有環(huán)
-
【3*】兩個鏈表的第一個公共節(jié)點(提示:考慮鏈表有環(huán)的情況)
public static ListNode findFirstCommonNode(ListNode head1, ListNode head2) { int length1 = getListLength(head1); int length2 = getListLength(head2); int diff = length1 - length2; ListNode longListHead = head1; ListNode shortListHead = head2; if (diff < 0) { longListHead = head2; shortListHead = head1; diff = length2 - length1; } for (int i = 0; i < diff; i++) { longListHead = longListHead.next; } while (longListHead != null && shortListHead != null && longListHead != shortListHead) { longListHead = longListHead.next; shortListHead = shortListHead.next; } // 返回第一個相同的公共結點,如果沒有返回null return longListHead; } private static int getListLength(ListNode head) { int result = 0; while (head != null) { result++; head = head.next; } return result; }
【3】刪除鏈表中重復節(jié)點
樹喜每、二分
-
【2】一個序列务唐,它的形式是12349678,9是峰值带兜,經(jīng)歷了一個上升又下降的過程枫笛,找出里面的最大值的位置O(logN)
public static int findPeakElement(int [] nums){ if (nums.length ==1) return 0; int low = 0, high = nums.length - 1, mid; while (low+1 < high) { mid = low + ((high - low) >> 1); if (nums[mid] < nums[mid - 1]) high = mid; //上坡 else if (nums[mid] < nums[mid+1]) low = mid; //下坡 else return mid; } return nums[low ] >nums[high] ?low:high; }
-
【2】深度優(yōu)先遍歷二叉樹,其實就是前序遍歷
public void depthOrderTraversal(){ if(root==null){ System.out.println("empty tree"); return; } ArrayDeque<TreeNode> stack=new ArrayDeque<TreeNode>(); stack.push(root); while(stack.isEmpty()==false){ TreeNode node=stack.pop(); System.out.print(node.value+" "); if(node.right!=null){ stack.push(node.right); } if(node.left!=null){ stack.push(node.left); } } System.out.print("\n"); }
-
【2】二叉樹廣度優(yōu)先遍歷
public void levelOrderTraversal(){ if(root==null){ System.out.println("empty tree"); return; } ArrayDeque<TreeNode> queue=new ArrayDeque<TreeNode>(); queue.add(root); while(queue.isEmpty()==false){ TreeNode node=queue.remove(); //從隊頭移除 System.out.print(node.value+" "); if(node.left!=null){ queue.add(node.left); } if(node.right!=null){ queue.add(node.right); } } System.out.print("\n"); }
-
前序遍歷二叉樹
public void preOrderTraverse1(TreeNoderoot){ if(root!=null){ System.out.print(root.val+""); preOrderTraverse1(root.left); preOrderTraverse1(root.right); } } //非遞歸 public void preOrderTraverse2(TreeNoderoot){ LinkedList<TreeNode>stack=newLinkedList<>(); TreeNodepNode=root; while(pNode!=null||!stack.isEmpty()){ if(pNode!=null){ System.out.print(pNode.val+""); stack.push(pNode); pNode=pNode.left; }else{//pNode==null&&!stack.isEmpty() TreeNodenode=stack.pop(); pNode=node.right; } } }
-
中序遍歷二叉樹
public void inOrderTraverse1(TreeNoderoot){ if(root!=null){ inOrderTraverse1(root.left); System.out.print(root.val+""); inOrderTraverse1(root.right); } } //非遞歸 public void inOrderTraverse2(TreeNoderoot){ LinkedList<TreeNode>stack=newLinkedList<>(); TreeNodepNode=root; while(pNode!=null||!stack.isEmpty()){ if(pNode!=null){ stack.push(pNode); pNode=pNode.left; }else{//pNode==null&&!stack.isEmpty() TreeNodenode=stack.pop(); System.out.print(node.val+""); pNode=node.right; } } }
-
【2】輸入一棵二叉樹的根結點,求該樹的深度
public static int treeDepth(BinaryTreeNode root) { if (root == null) { return 0; } int left = treeDepth(root.left); int right = treeDepth(root.right); return left > right ? (left + 1) : (right + 1); }
【3】根據(jù)中序和后序遍歷結果重建二叉樹
-
【3】根據(jù)中序和前序遍歷結果重建二叉樹
public static BinaryTreeNode construct(int[] preorder, int ps, int pe, int[] inorder, int is, int ie) { // 開始位置大于結束位置說明已經(jīng)沒有需要處理的元素了 if (ps > pe) { return null; } // 取前序遍歷的第一個數(shù)字,就是當前的根結點 int value = preorder[ps]; int index = is; // 在中序遍歷的數(shù)組中找根結點的位置 while (index <= ie && inorder[index] != value) { index++; } // 如果在整個中序遍歷的數(shù)組中沒有找到,說明輸入的參數(shù)是不合法的,拋出異常 if (index > ie) { throw new RuntimeException("Invalid input"); } // 創(chuàng)建當前的根結點,并且為結點賦值 BinaryTreeNode node = new BinaryTreeNode(); node.value = value; // 遞歸構建當前根結點的左子樹,左子樹的元素個數(shù):index-is+1個 // 左子樹對應的前序遍歷的位置在[ps+1, ps+index-is] // 左子樹對應的中序遍歷的位置在[is, index-1] node.left = construct(preorder, ps + 1, ps + index - is, inorder, is, index - 1); // 遞歸構建當前根結點的右子樹,右子樹的元素個數(shù):ie-index個 // 右子樹對應的前序遍歷的位置在[ps+index-is+1, pe] // 右子樹對應的中序遍歷的位置在[index+1, ie] node.right = construct(preorder, ps + index - is + 1, pe, inorder, index + 1, ie); // 返回創(chuàng)建的根結點 return node; }
-
【2】翻轉二叉樹
public static void mirror(BinaryTreeNode node) { // 如果當前結點不為空則進行操作 if (node != null) { // 下面是交換結點左右兩個子樹 BinaryTreeNode tmp = node.left; node.left = node.right; node.right = tmp; // 對結點的左右兩個子樹進行處理 mirror(node.left); mirror(node.right); } }
-
【3】判斷某個數(shù)組是不是二叉樹的后序遍歷結果 (劍指 offer 第 24 題)
public static boolean verifySequenceOfBST(int[] sequence, int start, int end) { // 如果對應要處理的數(shù)據(jù)只有一個或者已經(jīng)沒有數(shù)據(jù)要處理(start>end)就返回true if (start >= end) { return true; } // 從左向右找第一個不大于根結點(sequence[end])的元素的位置 int index = start; while (index < end - 1 && sequence[index] < sequence[end]) { index++; } // 執(zhí)行到此處[end, index-1]的元素都是小于根結點的(sequence[end]) // [end, // index-1]可以看作是根結點的左子樹 // right用于記錄第一個不小于根結點的元素的位置 int right = index; // 接下來要保證[index, end-1]的所有元素都是大于根根點的【A】 // 因為[index, end-1]只有成為根結點的右子樹 // 從第一個不小于根結點的元素開始,找第一個不大于根結點的元素 while (index < end - 1 && sequence[index] > sequence[end]) { index++; } // 如果【A】條件滿足,那么一定有index=end-1, // 如果不滿足那說明根結點的右子樹[index, end-1]中有小于等于根結點的元素, // 不符合二叉搜索樹的定義,返回false if (index != end - 1) { return false; } // 執(zhí)行到此處說明直到目前為止,還是合法的 // [start, index-1]為根結點左子樹的位置 // [index, end-1]為根結點右子樹的位置 index = right; return verifySequenceOfBST(sequence, start, index - 1) && verifySequenceOfBST(sequence, index, end - 1); }
-
【3】二叉樹中和為某個值的路徑
public static void findPath(BinaryTreeNode root, int curSum, int expectedSum, List<Integer> result) { // 如果結點不為空就進行處理 if (root != null) { // 加上當前結點的值 curSum += root.value; // 將當前結點入隊 result.add(root.value); // 如果當前結點的值小于期望的和 if (curSum < expectedSum) { // 遞歸處理左子樹 findPath(root.left, curSum, expectedSum, result); // 遞歸處理右子樹 findPath(root.right, curSum, expectedSum, result); } // 如果當前和與期望的和相等 else if (curSum == expectedSum) { // 當前結點是葉結點,則輸出結果 if (root.left == null && root.right == null) { System.out.println(result); } } // 移除當前結點刚照,回溯吧 result.remove(result.size() - 1); } }
【3*】二叉樹中某個節(jié)點的下一個節(jié)點 (強烈推薦準備一下刑巧,劍指 offer 第 58 題)
遞歸、動態(tài)規(guī)劃
- 股票買入賣出的最佳時間
public int maxProfit(int num[]){ int max=-1; int ans=-1; for(inti=len-1;i>=0;i--) if(num[i]>max) max=num[i]; if(max-num[i]>ans) ans=max-num[i]; return ans; }
- 【2】遞歸方法求數(shù)組的最大值
int max(int arr[], int len) { if (1 == len){ // 只有一個元素 return arr[0]; } int a = arr[0]; // 第一個元素 int b = max(arr + 1, len - 1); // 第二個元素起的最大值 return a > b ? a : b; }
- 【2】背包問題
- 【3】連續(xù)子數(shù)組的最大和
- 【4】實現(xiàn)簡單的正則表達式匹配
字符串
-
【2】給一串字符串比如abbbcccd无畔,輸出a1b3c3d1,O(n)
public static void main(String[] args) { String str= "abbbcccd"; int[] count= new int[256]; for (int i = 0 ;i<str.length();i++) { count[str.charAt(i)]++; } for (int i = 0;i<256;i++) { if(count[i]>0){ System.out.printf("%c%d",i,count[i]); } } }
-
【2】例如輸入字符串”I am a student. ”,則輸出”student. a am I”
public static void reverse(char[] data, int start, int end) { if (data == null || data.length < 1 || start < 0 || end > data.length || start > end) { return; } while (start < end) { char tmp = data[start]; data[start] = data[end]; data[end] = tmp; start++; end--; } } public static char[] reverseSentence(char[] data) { if (data == null || data.length < 1) { return data; } reverse(data, 0, data.length - 1);// 首先全局逆轉 int start = 0; int end = 0; while (start < data.length) { if (data[start] == ' ') { // 排除開頭空格 start++; end++; } else if (end == data.length || data[end] == ' ') {// 單詞結束邊界 reverse(data, start, end - 1); end++; start = end; } else { end++; } } return data; }
-
【2】比如輸入字符串”abcefg”和數(shù)字 2,該函數(shù)將返回左旋轉 2 位得到的結”cdefab”
public static void reverse(char[] data, int start, int end) { if (data == null || data.length < 1 || start < 0 || end > data.length || start > end) { return; } while (start < end) { char tmp = data[start]; data[start] = data[end]; data[end] = tmp; start++; end--; } } public static char[] leftRotateString(char[] data, int n) { if (data == null || n < 0 || n > data.length) { return data; } reverse(data, 0, data.length - 1); reverse(data, 0, data.length - n - 1); reverse(data, data.length - n, data.length - 1); return data; }
-
【2】java判斷是否是回文字符
public static boolean isPalidrome(Stringstr){ char[] ch=str.toCharArray(); int len=ch.length; for(inti=0,intj=len-1;i<=j;){ if(ch[i++]==ch[j--]){ }else{ return false; } } return ture; }
【3】最長回文子串
【3】最長無重復子串
【1*】字符串轉數(shù)字
【4】KMP 算法
-
【2】字符串全排列
public static void permutation(char[] chars, int begin) { // 如果是最后一個元素了,就輸出排列結果 if (chars.length - 1 == begin) { System.out.print(new String(chars) + " "); } else { char tmp; // 對當前還未處理的字符串進行處理,每個字符都可以作為當前處理位置的元素 for (int i = begin; i < chars.length; i++) { // 下面是交換元素的位置 tmp = chars[begin]; chars[begin] = chars[i]; chars[i] = tmp; // 處理下一個位置 permutation(chars, begin + 1); // 恢復 tmp = chars[begin]; chars[begin] = chars[i]; chars[i] = tmp; } } }```
【2*】翻轉字符串
排序
- 歸并排序啊楚、拓展:求數(shù)組中的逆序?qū)€數(shù)
- 快速排序 重點:partion 函數(shù)的實現(xiàn)
- 堆排序
- 數(shù)組元素值域已知時,考慮 基數(shù)排序 和 桶排序
大數(shù)據(jù)
1.【3】海量N個數(shù)中求前M大個數(shù)(選擇第M大數(shù))
數(shù)組檩互、矩陣
- 回形矩陣
public static void spiralOrderPrint(int[][] matrix) { int tR = 0; int tC = 0; int dR = matrix.length - 1; int dC = matrix[0].length - 1; while (tR <= dR && tC <= dC) { printEdge(matrix, tR++, tC++, dR--, dC--); } } public static void printEdge(int[][] m, int tR, int tC, int dR, int dC) { if (tR == dR) { // 子矩陣只有一行時 for (int i = tC; i <= dC; i++) { System.out.print(m[tR][i] + " "); } } else if (tC == dC) { // 子矩陣只有一列時 for (int i = tR; i <= dR; i++) { System.out.print(m[i][tC] + " "); } } else { // 一般情況 int curC = tC; int curR = tR; while (curC != dC) { System.out.print(m[tR][curC] + " "); curC++; } while (curR != dR) { System.out.print(m[curR][dC] + " "); curR++; } while (curC != tC) { System.out.print(m[dR][curC] + " "); curC--; } while (curR != tR) { System.out.print(m[curR][tC] + " "); curR--; } } }```
- 蛇形矩陣
- 【2】在排序數(shù)組中查找和為給定值的兩個數(shù)字(思路)
- 找到數(shù)組的第一個數(shù)字和最后一個數(shù)字特幔。
- 當兩個數(shù)字的和大于輸入的數(shù)字時,把較大的數(shù)字往前移動闸昨;
- 當兩個數(shù)字的和小于數(shù)字時蚯斯,把較小的數(shù)字往后移動薄风;
- 當相等時,輸出等式拍嵌。這樣掃描的順序是從數(shù)組的兩端向數(shù)組的中間掃描遭赂。
位運算
- 【2】給一個十進制數(shù)字,求它的二進制表示中横辆,有多少個 1 (n &= n - 1)
- 【3】給一個數(shù)組撇他,所有數(shù)字都出現(xiàn)了偶數(shù)次,只有一個出現(xiàn)了一次狈蚤,找出這個數(shù)
- 【4】給一個數(shù)組困肩,所有數(shù)字都出現(xiàn)了三次,只有一個出現(xiàn)了一次脆侮,找出這個數(shù)
- 【3】給一個數(shù)組锌畸,所有數(shù)組都出現(xiàn)了偶數(shù)次,只有兩個數(shù)字出現(xiàn)了一次靖避,找出這兩個數(shù)
JAVA相關題
-
【2】生產(chǎn)者/消費者(wait() / notify()方法)
public class Storage { // 倉庫最大存儲量 private final int MAX_SIZE = 100; // 倉庫存儲的載體 private LinkedList<Object> list = new LinkedList<Object>(); // 生產(chǎn)num個產(chǎn)品 public void produce(int num) { // 同步代碼段 synchronized (list) { // 如果倉庫剩余容量不足 while (list.size() + num > MAX_SIZE) { try { list.wait(); // 由于條件不滿足潭枣,生產(chǎn)阻塞 } catch (InterruptedException e) { e.printStackTrace(); } } // 生產(chǎn)條件滿足情況下,生產(chǎn)num個產(chǎn)品 for (int i = 1; i <= num; ++i) { list.add(new Object()); } list.notifyAll(); } } // 消費num個產(chǎn)品 public void consume(int num) { // 同步代碼段 synchronized (list) { // 如果倉庫存儲量不足 while (list.size() < num) { try { list.wait(); // 由于條件不滿足幻捏,消費阻塞 } catch (InterruptedException e) { e.printStackTrace(); } } // 消費條件滿足情況下盆犁,消費num個產(chǎn)品 for (int i = 1; i <= num; ++i) { list.remove(); } list.notifyAll(); } } }
-
【3】生產(chǎn)者/消費者(await() / signal()方法)
public class Storage { // 倉庫最大存儲量 private final int MAX_SIZE = 100; // 倉庫存儲的載體 private LinkedList<Object> list = new LinkedList<Object>(); // 鎖 private final Lock lock = new ReentrantLock(); // 倉庫滿的條件變量 private final Condition full = lock.newCondition(); // 倉庫空的條件變量 private final Condition empty = lock.newCondition(); // 生產(chǎn)num個產(chǎn)品 public void produce(int num) { // 獲得鎖 lock.lock(); // 如果倉庫剩余容量不足 while (list.size() + num > MAX_SIZE) { try { full.await(); // 由于條件不滿足,生產(chǎn)阻塞 } catch (InterruptedException e) { e.printStackTrace(); } } // 生產(chǎn)條件滿足情況下篡九,生產(chǎn)num個產(chǎn)品 for (int i = 1; i <= num; ++i) { list.add(new Object()); } // 喚醒其他所有線程 full.signalAll(); empty.signalAll(); // 釋放鎖 lock.unlock(); } // 消費num個產(chǎn)品 public void consume(int num) { // 獲得鎖 lock.lock(); // 如果倉庫存儲量不足 while (list.size() < num) { try { empty.await(); // 由于條件不滿足谐岁,消費阻塞 } catch (InterruptedException e) { e.printStackTrace(); } } // 消費條件滿足情況下,消費num個產(chǎn)品 for (int i = 1; i <= num; ++i) { list.remove(); } // 喚醒其他所有線程 full.signalAll(); empty.signalAll(); // 釋放鎖 lock.unlock(); } }
-
【2】生產(chǎn)者/消費者(BlockingQueue阻塞隊列方法)
public class Storage { // 倉庫最大存儲量 private final int MAX_SIZE = 100; // 倉庫存儲的載體 private LinkedBlockingQueue<Object> list = new LinkedBlockingQueue<Object>(100); // 生產(chǎn)num個產(chǎn)品 public void produce(int num) { // 如果倉庫剩余容量為0 if (list.size() == MAX_SIZE) { System.out.println("暫時不能執(zhí)行生產(chǎn)任務!"); } // 生產(chǎn)條件滿足情況下瓮下,生產(chǎn)num個產(chǎn)品 for (int i = 1; i <= num; ++i) { try { // 放入產(chǎn)品翰铡,自動阻塞 list.put(new Object()); } catch (InterruptedException e) { e.printStackTrace(); } } } // 消費num個產(chǎn)品 public void consume(int num) { // 如果倉庫存儲量不足 if (list.size() == 0) { System.out.println("暫時不能執(zhí)行消費任務!"); } // 消費條件滿足情況下,消費num個產(chǎn)品 for (int i = 1; i <= num; ++i) { try { // 消費產(chǎn)品讽坏,自動阻塞 list.take(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
【3】觀察者設計模式
public class SimpleObservable extends Observable{ private int data = 0; public int getData(){ return data; } public void setData(int i){ if(this.data != i) { this.data = i; setChanged(); //只有在setChange()被調(diào)用后,notifyObservers()才會去調(diào)用update()例证,否則什么都不干路呜。 notifyObservers(); } } } public class SimpleObserver implements Observer{ public SimpleObserver(SimpleObservable simpleObservable){ simpleObservable.addObserver(this ); } public void update(Observable observable ,Object data){ // data為任意對象,用于傳遞參數(shù) System.out.println(“Data has changed to” + (SimpleObservable)observable.getData()); } } public class SimpleTest{ public static void main(String[] args){ SimpleObservable doc = new SimpleObservable (); SimpleObserver view = new SimpleObserver (doc); doc.setData(1); doc.setData(2); doc.setData(2); doc.setData(3); } }