Java实现查找树(BST,AVL,BTree,Trie)
来源:互联网 发布:windows update有用吗 编辑:程序博客网 时间:2024/05/22 07:06
BST
二叉排序树是一种非常简单的排序树(或者说查找树)
包括两种操作
添加
添加的元素永远是叶子节点
删除
- 叶子节点,直接删除
- 非叶子节点
2.1. 只有左子树或者只有右子树,直接用左子树或者右子树代替待删除节点
2.2. 如果左右子树都存在,则将右子树接到左子树的最右边节点的右子树下,这样就依然保持了有序
import java.util.*;/** 二分法查找*/public class BST{ public static Node root = null; public static void main(String[] args) { System.out.println("Hello World!"); int[] values = createValue(); //int[] values = {10,8,13,4,14,2,6,1,3,5,7}; //int[] values = {1}; //int[] values = {10,8,4,2,6,1,3,5,7}; System.out.println(Arrays.toString(values)); createBST(values); printBST(root); System.out.println(); System.out.print("Pls. select a operation(s for search, a for add, d for delete, q for quit,p for print):"); Scanner scan = new Scanner(System.in); String str = scan.next(); char select = str.charAt(0); while(true){ if(select == 'q'){ break; } int key = 0; switch (select) { case 'a': System.out.println(); System.out.print("(a)Input a integer:"); key = scan.nextInt(); addNode(key); printBST(root); break; case 'd': System.out.println(); System.out.print("(d)Input a integer:"); key = scan.nextInt(); deleteNode(key); printBST(root); break; case 'p': printBST(root); break; case 's': System.out.println(); System.out.print("(s)Input a integer:"); key = scan.nextInt(); if(search(key)){ System.out.println(key + "存在!"); }else{ System.out.println(key + "不存在!"); } break; } System.out.println(); System.out.print("Pls. select a operation(s for search, a for add, d for delete, q for quit,p for print):"); str = scan.next(); select = str.charAt(0); } } /* * 产生随机的整数数组 */ public static int[] createValue(){ int size = new Random().nextInt(20); while(size == 0){ size = new Random().nextInt(20); } int[] values = new int[size]; for(int i = 0; i < size ; i ++ ){ values[i] = new Random().nextInt(20000); } return values; } /* * 构造BST * */ public static void createBST(int[] value){ for(int i = 0; i < value.length; i ++){ addNode(value[i]); } } /* * 中序遍历BST */ public static void printBST(Node p){ if(p == null){ return; }else{ printBST(p.left); System.out.print(p.key+","); printBST(p.right); } //System.out.println(); } /* * 查找 */ public static boolean search(int key){ Node p = root; while(p != null){ if(p.key == key){ return true; }else if(key < p.key){ p = p.left; }else{ p = p.right; } } return false; } /* * 添加节点 */ public static boolean addNode(int key){ //BST 是空树 if(root == null){ root = new Node(key); }else{ Node p = root; while(true){ int tmp = p.key; if(key == tmp ){ return false; }else if(key < p.key){ if(p.left == null){ Node q = new Node(key); p.left = q; return true; }else{ p = p.left; } }else{ if(p.right == null){ Node q = new Node(key); p.right = q; return true; }else{ p = p.right; } } } } return true; } /* * 删除节点 */ public static boolean deleteNode(int key){ Node q = null; Node p = root; //标识当前节点是父节点的左节点(true) //还是父节点的右节点(false) boolean flag = false; while(p != null){ System.out.println("p.key:"+p.key); if(p.key == key){ //p是叶子节点 if(p.left == null && p.right == null){ if(q == null){ root = null; }else{ if(flag){ q.left = null; }else{ q.right = null; } } } //p的左子树或右子树是空 else if(p.left == null || p.right == null){ if(q == null){ root = (p.left == null ? p.right: p.left); }else{ if(flag){ q.left = (p.left == null ? p.right: p.left); }else{ q.right = (p.left == null ? p.right: p.left); } } } //左右子树都不为空 else{ Node k = p.left; while(k.right != null){ k = k.right; } if(q == null){ k.right = p.right; root = p.left; }else{ k.right = p.right; q.left = p.left; } } return true; }else if(key < p.key){ q = p; p = p.left; flag = true; }else{ q = p; p = p.right; flag = false; } } return false; }}
AVL
这是一种比BST高效的平衡二叉树,
高度为 h 的 AVL 树,节点数 N 最多2^h − 1; 最少N(h)=N(h− 1) +N(h− 2) + 1。
查找、插入和删除在平均和最坏情况下都是O(log n)
主要是几个旋转操作
左旋,右旋,双向旋转(先左后右,先右后左)
import java.util.*;/** 自平衡二叉查找树*/public class AVL { private static Node root = null; private static int count = 0; public static void main(String[] args) { System.out.println("Hello World!"); int[] values = createData(); System.out.println("原始数组:" + Arrays.toString(values)); createAVL(values); printAVL(); //System.out.println(height(root.left)); //System.out.println(height(root.right)); } /* * 创建测试数据 */ public static int[] createData(){ int size = new Random().nextInt(20); while(size == 0){ size = new Random().nextInt(20); } int[] values = new int[size]; for(int i = 0; i < size; i ++){ values[i] = new Random().nextInt(100); } return values; } /* * 构造树 */ public static void createAVL(int[] values){ for(int i = 0; i < values.length; i ++){ addNode(values[i]); } } /* * 添加节点 */ public static void addNode(int key){ Node tmp = new Node(key); if(root == null){ root = tmp; }else{ insert(tmp); balance(tmp); } } /* * 插入节点 */ public static void insert(Node tmp){ Node q = root; while(true){ if(tmp.key == q.key){ return; }else if(tmp.key < q.key){ if(q.left == null){ q.left = tmp; break; } q = q.left; }else{ if(q.right == null){ q.right = tmp; break; } q = q.right; } } } /* * 平衡节点 * 由于插入tmp节点,树失去了平衡 */ public static void balance(Node tmp){ //p是离插入节点最近的非平衡节点 Node p = null; //q用来遍历AVL树 Node q = null; q = root; //1. 寻找离tmp最近的非平衡点q while(q != null){ int hL = height(q.left); int hR = height(q.right); if(((hL - hR) == 2) || ((hL - hR)== -2)){ //此节点是非平衡点,用p标记 p = q; } if(tmp.key < q.key){ q = q.left; }else if(tmp.key > q.key){ q = q.right; }else{ q = null; } } if(p == null){ //不存在非平衡点 return; } //2. 判断属于哪种情况 //2.1 在p的左孩子的左子树中插入节点-- 右旋 //2.2 在p的左孩子的右子树中插入节点-- 先左再右 //2.3 在p的右孩子的左子树中插入节点-- 先右再左 //2.4 在p的右孩子的右子树中插入节点-- 左旋 if(tmp.key < p.key){ if(tmp.key < p.left.key){ //右旋 singleRotate(p,false); //System.out.println("平衡之后:"); //printAVL(); }else{ //左-右,先左旋后右旋 //System.out.println("左-右"); doubleRotate(p,true); } }else{ if(tmp.key > p.right.key){ //左旋 singleRotate(p,true); }else{ //右-左 //System.out.println("右-左"); doubleRotate(p,false); } } } /* * 将以p为根的树单次旋转 */ public static void singleRotate(Node p,boolean flag){ //左旋 if(flag){ Node r = p.right; Node tmp = Node.copy(p); tmp.right = r.left; p.right = r.right; p.key = r.key; p.left = tmp; } //右旋 else{ Node left = p.left; Node tmp = Node.copy(p); tmp.left = left.right; p.left = left.left; p.key = left.key; p.right = tmp; } } /* * 以p为根的双旋 */ public static void doubleRotate(Node p,boolean flag){ //先左旋后右旋 if(flag){ Node q = p.left; singleRotate(q,true); singleRotate(p,false); } //先右旋后左旋 else{ Node q = p.right; singleRotate(q,false); singleRotate(p,true); } } /* * 二叉树的高度 */ public static int height(Node p){ if(p == null){ return 0; } int hL = height(p.left); int hR = height(p.right); return (hL > hR ? hL: hR) + 1; } /* * 按层次输出树,空节点以"N"表示 */ public static void printAVL(){ Queue<Node> queue = new LinkedList<Node>(); System.out.print("["); if(root != null){ queue.offer(root); Node p = null; while(!queue.isEmpty()){ p = queue.poll(); if(p != null){ System.out.print(p.key+","); if(p.left != null){ queue.offer(p.left); }else{ queue.offer(null); } if(p.right != null){ queue.offer(p.right); }else{ queue.offer(null); } } else System.out.print("N,"); } } System.out.println("]"); }}class Node{ /* * balanceFactor=H(left) - H(right) */ int key = 0; Node left; Node right; public Node(int key){ this.key = key; } public static Node copy(Node p){ Node tmp = new Node(p.key); tmp.left = p.left; tmp.right = p.right; return tmp; }}
BTree
平衡多路查找树
import java.util.*;/** m阶的B-树,或为空树,或为满足下列特性的m叉树* 1. 树中每个节点至多有m棵子树(m-1个关键字)* 2. 若根节点不是叶子节点则至少有两棵子树* 3. 除根之外的所有非终端节点至少有ceil(m/2)棵子树(ceil(m/2)-1个关键字)* 4. 所有的非终端节点中包含下列信息数据* (n,A0,K1,A1,K2,A2,...,Kn,An)* 其中:Ki(i=1,...,n)为关键字,且Ki<Ki+1(i=1,...,n-1);* Ai(i=0,...,n)为指向子树根节点的指针,* 且指针Ai-1所指子树中所有节点的关键字均小于Ki(i=1,...,n)* An所指子树中所有节点的关键字均大于Kn,n(ceil(m/2)-1 <= n <= m-1)为关键字的个数* 5. 所有的叶子节点都出现在同一层次上,并且不带信息(可以看做是外部节* 点或查找失败的节点,实际上这些节点不存在,指向这些节点的指针为空)* * 分裂时,将(关键字-1)一分为二,然后将中间的放到父节点中* 分裂函数写的时候,要注意父节点指针的更改*/public class BTree { //表示这棵BTree是m阶,每个节点最多M棵子树,M-1个关键字 private static final int M; //每个节点至少MIN_KEY_NUM个子树,MIN_KEY_NUM - 1 个关键字 private static final int MIN_KEY_NUM; private static BTreeNode root; static{ M = 3; //注意是2.0,而不是2 MIN_KEY_NUM = (int)Math.ceil(M/2.0); } public static void main(String[] args) { System.out.println("Hello World!"); int count = new Random().nextInt(10); while(count == 0){ count = new Random().nextInt(10); } int[] arr = new int[count]; for(int i = 0; i < count ; i ++){ arr[i] = new Random().nextInt(100); } int[] arr1 = {62,65,92}; System.out.println(Arrays.toString(arr)); createBTree(arr); printBTree(); System.out.println("============删除==============="); while(count > 0){ int index = new Random().nextInt(count); System.out.println("删除:" + arr[index]); delete(arr[index]); printBTree(); for(int i = 0; i < count ; i ++){ if(i > index){ arr[i - 1] = arr[i]; } } count--; } } public static void createBTree(int[] arr){ for(int i = 0; i < arr.length ; i ++){ //System.out.println(i); add(arr[i]); } } public static void add(int key){ //根为空 if(root == null){ root = new BTreeNode(); root.keys[++root.keyNum] = key; root.parrent = null; return; } BTreeNode p = root; label: while(true){ //插入排序 int i = 0; for(i = p.keyNum; i >= 1 ; i--){ //找寻插入点 if(key > p.keys[i]){ break; } if(key == p.keys[i]){ return; } } if(p.childs[i] == null){ //插入点为i+1 for(int j = p.keyNum ; j >= (i + 1); j--){ p.keys[j + 1] = p.keys[j]; } p.keys[i + 1] = key; p.keyNum++; break label; }else{ p = p.childs[i]; } } //将key插入p之后,判断p节点是否符合BTree的条件 //每个节点的关键字最多M-1个 if(p.keyNum > M - 1){ //将p节点分裂 split(p); } } private static void split(BTreeNode p){ BTreeNode lt = new BTreeNode(); BTreeNode gt = new BTreeNode(); //分裂出来的左节点 /* * M = 3 * MIN_KEY_NUM = 2 * keys: * ----------------- * |0 |1 |2 |3 | * ----------------- * childs: * ----------------- * |0 |1 |2 |3 | * ----------------- * index = M 的值作为备用 */ System.arraycopy(p.keys,1,lt.keys,1,MIN_KEY_NUM - 1); System.arraycopy(p.childs,0,lt.childs,0,MIN_KEY_NUM); lt.keyNum = MIN_KEY_NUM - 1; //System.out.println(p.keys[MIN_KEY_NUM] + ":" + Arrays.toString(lt.keys)); System.arraycopy(p.keys,MIN_KEY_NUM + 1,gt.keys,1,M - MIN_KEY_NUM); System.arraycopy(p.childs,MIN_KEY_NUM,gt.childs,0,M - MIN_KEY_NUM + 1); gt.keyNum = M - MIN_KEY_NUM; //System.out.println(p.keys[MIN_KEY_NUM] + ":" + Arrays.toString(gt.keys)); /* * 分隔节点之后,需要更改父节点信息 */ for(int i = 0 ; i <= lt.keyNum ; i ++){ if(lt.childs[i] != null){ lt.childs[i].parrent = lt; } } for(int i = 0 ; i <= gt.keyNum ; i ++){ if(gt.childs[i] != null){ gt.childs[i].parrent = gt; } } BTreeNode parrent = p.parrent; //root节点分裂 if(parrent == null){ BTreeNode tmp = new BTreeNode(); tmp.keys[++tmp.keyNum] = p.keys[MIN_KEY_NUM]; tmp.parrent = null; tmp.childs[tmp.keyNum - 1] = lt; tmp.childs[tmp.keyNum] = gt; lt.parrent = tmp; gt.parrent = tmp; root = tmp; }else{ int i = 0; //System.out.println("parrent:"+Arrays.toString(parrent.keys)); //插入排序 for(i = parrent.keyNum; i >= 1 ; i--){ //找寻插入点 if(p.keys[MIN_KEY_NUM] > parrent.keys[i]){ break; } } //插入点为i+1 for(int j = parrent.keyNum ; j >= (i + 1); j--){ parrent.keys[j + 1] = parrent.keys[j]; parrent.childs[j + 1] = parrent.childs[j]; } parrent.keys[i + 1] = p.keys[MIN_KEY_NUM]; //System.out.println("parrent:"+Arrays.toString(parrent.keys)); parrent.childs[i] = lt; parrent.childs[i + 1] = gt; lt.parrent = parrent; gt.parrent = parrent; parrent.keyNum++; //System.out.println("parrent:"+parrent.keyNum); //是否继续分裂 if(parrent.keyNum > M - 1){ //将p节点分裂 split(parrent); } } } /* * 删除节点i中的key * 1. 节点i不是最底层非终端节点 * 将Ai子树上的最小值替换key * 问题变为2 * 2. 节点i是最底层非终端节点 * 2.1 节点i的关键字个数 >= MIN_KEY_NUM,直接删除 * 2.2 节点i的关键字个数 = MIN_KEY_NUM - 1 * 2.2.1 兄弟节点的关键字个数 >= MIN_KEY_NUM,将右兄弟最小值(左兄弟最大值)上移至父节点相应位置的数据,然后将父节点被替换的数据下移至被删除节点 * 2.2.2 兄弟节点的关键字个数 = MIN_KEY_NUM - 1,合并(借助父节点) * */ public static void delete(int key){ //System.out.println("deletekey:" + key); //遍历BTree,查找key所在的节点 BTreeNode p = root; int index = 0; label: while(p != null){ //System.out.println("p.keyNum:" + p.keyNum); //System.out.println("p:" + Arrays.toString(p.keys)); for(int i = p.keyNum; i >= 1; i --){ if(key == p.keys[i]){ index = i; break label; }else if(key > p.keys[i]){ p = p.childs[i]; continue label; } } p = p.childs[0]; } if(p == null){ return ; } //System.out.println("p.keyNum:" + p.keyNum); //System.out.println("p:" + Arrays.toString(p.keys)); //找到p if(p.childs[0] == null){ delete(p,key); }else{ //对于不是最底层的非终端节点,则将别比key小的最大值替换key BTreeNode q = p.childs[index - 1]; while(q.childs[0] != null){ q = q.childs[q.keyNum]; } p.keys[index] = q.keys[q.keyNum]; delete(q,q.keys[q.keyNum]); } } public static void delete(BTreeNode p,int key){ if(p.keyNum >= MIN_KEY_NUM){ //删除后节点关键字数满足MIN_KEY_NUM - 1,直接删除 for(int i = 1; i <= p.keyNum; i ++){ if(p.keys[i] > key){ p.keys[i - 1] = p.keys[i]; } } p.keys[p.keyNum] = 0; p.keyNum--; }else{ //删除后节点关键字数不能够满足MIN_KEY_NUM - 1,可能需要合并 int index = 0; BTreeNode q = p.parrent; if(q == null){ //p是root,直接删除,因为root至少两棵子树,所以关键字个数没有限制 for(int i = 1; i <= p.keyNum; i ++){ if(p.keys[i] > key){ p.keys[i - 1] = p.keys[i]; } } p.keys[p.keyNum] = 0; p.keyNum--; return; } for(int i = 0; i <= q.keyNum ; i ++){ if(q.childs[i] == p){ index = i; break; } } //查询右兄弟并且右兄弟的关键字个数大于MIN_KEY_NUM - 1, //将父节点中第一个大于key的值移动到删除节点 //将右兄弟中的最小值替换父节点中的第一个大于key的值 if(index < q.keyNum && q.childs[index + 1].keyNum >= MIN_KEY_NUM){ for(int i = 0 ; i <= p.keyNum ; i ++){ if(p.keys[i] > key){ p.keys[i - 1] = p.keys[i]; } } p.keys[p.keyNum] = q.keys[index + 1]; q.keys[index + 1] = q.childs[index + 1].keys[1]; for(int i = 2; i <= q.childs[index + 1].keyNum ; i ++){ q.childs[index + 1].keys[i - 1] = q.childs[index + 1].keys[i]; } q.childs[index + 1].keys[q.childs[index + 1].keyNum] = 0; q.childs[index + 1].keyNum--; return; } //查询左兄弟并且左兄弟的关键字个数大于MIN_KEY_NUM - 1 //将父节点中最后一个小于key的值移动到删除节点 //将左兄弟中的最大值替换父节点中的最后一个小于key的值 if(index > 0 && q.childs[index - 1].keyNum >= MIN_KEY_NUM){ for(int i = p.keyNum ; i >= 1 ; i --){ if(p.keys[i] < key){ p.keys[i + 1] = p.keys[i]; } } p.keys[1] = q.keys[index]; q.keys[index] = q.childs[index - 1].keys[q.childs[index - 1].keyNum]; q.childs[index - 1].keys[q.childs[index - 1].keyNum] = 0; q.childs[index - 1].keyNum--; return; } //不符合上述条件,则需要有merge操作 //删除key,然后和兄弟合并 for(int i = 1 ; i < p.keyNum; i++){ if(p.keys[i] > key){ p.keys[i - 1] = p.keys[i]; } } //将最后一个值赋值为0 p.keys[p.keyNum] = 0; p.keyNum--; if(index < q.keyNum){ //将节点与右节点结合 merge(p,true); }else{ //将节点与左节点结合 merge(p,false); } } } public static void merge(BTreeNode p,boolean flag){ BTreeNode q = p.parrent; int index = 0; for(int i = 0; i <= q.keyNum ; i++){ if(q.childs[i] == p){ index = i; } } if(flag){ //将节点与右节点结合 BTreeNode br = q.childs[index + 1]; //System.out.print("br.keyNum:" + br.keyNum); //System.out.println("\t\t\t" + Arrays.toString(br.keys)); p.keys[++p.keyNum] = q.keys[index + 1]; for(int i = index + 1; i <= q.keyNum; i++){ q.keys[i] = q.keys[i + 1]; q.childs[i] = q.childs[i + 1]; } q.keyNum --; //if(br.keyNum > 0){ System.arraycopy(br.keys,1,p.keys,p.keyNum + 1,br.keyNum); System.arraycopy(br.childs,0,p.childs,p.keyNum,br.keyNum + 1); p.keyNum += br.keyNum; //} if(q == root){ if(q.keyNum == 0){ root = p; p.parrent = null; for(int i = 0; i <= p.keyNum; i ++){ if(p.childs[i] != null){ p.childs[i].parrent = root; } } } }else{ if(q.keyNum < MIN_KEY_NUM - 1){ BTreeNode q1 = q.parrent; int index1 = 0; for(int i = 0; i <= q1.keyNum ; i++){ if(q1.childs[i] == q){ index1 = i; } } if(index1 < q1.keyNum){ merge(q,true); }else{ merge(q,false); } } } }else{ //将节点与左节点结合 BTreeNode lr = q.childs[index - 1]; merge(lr,true); } } public static void printBTree(){ Queue<BTreeNode> queue = new LinkedList<BTreeNode>(); queue.offer(root); while(!queue.isEmpty()){ BTreeNode tmp = queue.poll(); if(tmp != null ){ System.out.print("keyNum:" + tmp.keyNum); System.out.print("\t\t" + Arrays.toString(tmp.keys)); System.out.println("\t\t\t\t" + tmp.parrent + "------" + tmp); //System.out.print("\t\t\t\t" + tmp); //System.out.println("\t\t\t\t\t\t" + tmp.parrent); for(int i = 0 ; i <= tmp.keyNum; i++){ queue.offer(tmp.childs[i]); } } } } static class BTreeNode { //指向父节点指针 public BTreeNode parrent; //本节点的关键字个数 public int keyNum; //关键字数组,最多M-1个关键字,0号元素不用,1个作为备用 public int[] keys = new int[M + 1]; //子树指针,最多M棵子树 public BTreeNode[] childs = new BTreeNode[M + 1]; }}
Trie
字典树
import java.util.*;/** 字典树* 1. 统计词频* 2. 字符串排序* 3. 最长公共前缀*/public class Trie { private TrieNode root; public Trie() { root = new TrieNode(); } public static void main(String[] args) { System.out.println("Hello World!"); } // Inserts a word into the trie. public void insert(String word) { TrieNode p = root; for(int i = 0; i < word.length();i++){ char c = word.charAt(i); if(p.nodes[c-'a'] == null){ TrieNode tmp = new TrieNode(c); p.nodes[c - 'a'] = tmp; p = tmp; }else{ p = p.nodes[c-'a']; } } p.flag = 1; } // Returns if the word is in the trie. public boolean search(String word) { TrieNode p = root; for(int i = 0; i < word.length();i++){ char c = word.charAt(i); if(p.nodes[c-'a'] == null){ return false; }else{ p = p.nodes[c-'a']; } } if(p.flag == 1){ return true; }else{ return false; } } // Returns if there is any word in the trie // that starts with the given prefix. public boolean startsWith(String prefix) { TrieNode p = root; for(int i = 0; i < prefix.length();i++){ char c = prefix.charAt(i); if(p.nodes[c-'a'] == null){ return false; }else{ p = p.nodes[c-'a']; } } return true; }}class TrieNode { // Initialize your data structure here. public char key; public TrieNode[] nodes; //flag == 1 表示是字符串 //flag == 0 表示是前缀 public int flag; //public int count;统计词频 public TrieNode() { key='\0'; nodes = new TrieNode[26]; } public TrieNode(char c){ key = c; nodes = new TrieNode[26]; flag = 0; }}
0 0
- Java实现查找树(BST,AVL,BTree,Trie)
- Java实现BST(二叉查找树)
- Java实现二叉查找树(BST)
- 查找(一):BST、AVL、红黑树
- 二叉查找树BST----java实现
- 二叉查找树BST----java实现
- 二叉查找树(BST) | 平衡二叉查找树(AVL) | 红黑树(RBT)
- 二叉查找树(BST)和平衡二叉查找树(AVL)
- trie字母查找树java实现
- 二叉查找树(BST)的实现
- 数据结构:二叉查找树(BST)&平衡二叉树(AVL)
- BST二叉查找树实现
- 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)的比较
- 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)的比较
- 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)的比较
- 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)的比较
- 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)的比较
- 二叉查找树(BST),平衡二叉查找树(AVL),红黑树(RBT),B~/B+树(B-tree)的比较
- 关于动态分布函数
- MyEclipse 10.7汉化教程
- Material Design之SwipeToRefresh下拉刷新
- .net mvc
- HTML5 中的 Web SQL Database 来构建应用程序
- Java实现查找树(BST,AVL,BTree,Trie)
- Linux 常用命令的使用
- HTTP跨域调用-传入URL就直接返回回来数据
- Struts2中action访问路径配置
- 上传iTunes的Bug
- mac上配置环境变量
- java.lang.OutOfMemoryError: PermGen space的解决方法
- WebDriver常见异常
- 数组名是指针常量