1.递归问题
1.1计算阶乘
package interview.recursion; import java.util.Scanner; public class Fact { public static void main(String[] args) { System.out.println("请输入n的值:"); Scanner in = new Scanner(System.in); int n = in.nextInt(); int num = fact(n); System.out.println(n + "的阶乘为:" + num); } public static int fact(int n) { if (n == 1) { return 1; } return n * fact(n - 1); } }
1.2计算斐波那契数列
Fibonacci sequence:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ……
package interview.recursion; import java.util.Scanner; public class Fib { public static int fib(int n) { if (n == 0) { return 0; } else if (n == 1) { return 1; } else { return fib(n - 1) + fib(n - 2); } } public static void main(String[] args) { System.out.println("请输入n的值:"); Scanner in = new Scanner(System.in); int n = in.nextInt(); int num = fib(n); System.out.println("第" + n + "个值的fib为:" + +num); } }
1.3计算最大公约数(辗转相除法)
package interview.recursion; import java.util.Scanner; public class Gcd { public static int gcd(int max, int min) { if (min == 0) { return max; } else { return gcd(min, max % min); } } public static void main(String[] args) { System.out.println("请输入max的值:"); Scanner in = new Scanner(System.in); int max = in.nextInt(); System.out.println("请输入min的值:"); int min = in.nextInt(); int num = gcd(max, min); System.out.println(max + "和" + min + "的最大公约数为:" + num); } }
1.4汉诺塔问题(递归)
问题描述
三个柱子,起初有若干个按大小关系顺序安放的盘子,需要全部移动到另外一个柱子上。移动规则:在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
移动次数: f(n)=2n -1
解法思路
使用递归算法进行处理。
汉诺塔的算法大概有3个步骤:
(1)把a上的n-1个盘通过c移动到b。
(2)把a上的最下面的盘移到c。
(3)因为n-1个盘全在b上了,所以把b当做a重复以上步骤就好了。
在网上找到一个3阶的汉诺塔递归过程示意图,参考一下。
package cn.jxufe.ch06_hanoitowers; public class HanoiTowers { /** * 汉诺塔问题:所有的盘子,刚开始都在塔座A上,要求将所有的盘子从塔座A移动到塔座C,每次只能移动一个盘子,且 * 任何盘子不能放在比自己小的盘子上。 * * @param topN:移动的盘子数 * @param from:从哪个塔座开始 * @param inter:中间塔座 * @param to;目标塔座 */ public static void doTower(int topN, char from, char inter, char to) { if (topN == 1) { System.out.println("盘子1,从" + from + "塔座到" + to + "塔座"); return; } else { doTower(topN - 1, from, to, inter); System.out.println("盘子" + topN + ",从" + from + "塔座到" + to + "塔座"); doTower(topN - 1, inter, from, to); } } }
package cn.jxufe.ch06_hanoitowers; public class TestHanoiTowers { public static void main(String[] args) { HanoiTowers.doTower(4,'A','B','C'); } }
1.5瓶盖问题
package test; /* * 描述:每 3 个可乐盖可兑换 1 瓶子可乐,求买 n 瓶可乐最终可获得的可乐瓶子数。 */ import java.util.Scanner; public class T03 { public static int times = 1; public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("输入购买的可乐数:"); times = 1; int j = input.nextInt(); int i = func(j); System.out.println("--------------------------"); System.out.println("总共可获得 " + i + " 瓶 "); } public static int func(int i) { if (i < 3) { System.out.println("最终剩下 " + i + " 个瓶盖,不足以兑换"); return i; } else { System.out.println("第 " + times++ + " 次兑换," + "本次兑换总共有 " + i + " 个瓶盖,用 " + (i - i % 3) + " 个瓶盖换了 " + i / 3 + " 瓶可乐,剩余 " + i % 3 + " 个瓶盖可用于下次兑换"); return ((i - i % 3) + func(i / 3 + i % 3)); } } }
1.6走楼梯
题目描述:
一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法。
思路:当n大于2的时候,每次可以选择走2级也可以选择走1级,所有都有两种方案。即f(n-1)+f(n-2)
package interview.recursion; import java.util.Scanner; public class Stairs { public static int solve(int n) { if (n == 1) { return 1; } else if (n == 2) { return 2; } else { return solve(n - 1) + solve(n - 2); } } public static void main(String[] args) { System.out.println("请输入n的值:"); Scanner in = new Scanner(System.in); int n = in.nextInt(); int num = solve(n); System.out.println("总共有" + num + "种走法"); } }
2.二叉树
2.1插入和查找
package cn.jxufe.ch07_tree; /** * 二叉树节点 */ public class Node { //数据项 public int data; public String sdata; public Node leftChild; public Node rightChild; public Node(int data,String sdata) { this.data = data; this.sdata =sdata; } }
package cn.jxufe.ch07_tree; /** * 二叉树 */ public class Tree { //根节点 public Node root; /** * 插入节点 */ public void insert(int value,String sdata) { //封装节点 Node newNode = new Node(value,sdata); //引用当前节点 Node current = root; //引用父节点 Node parent; //如果root为null,也就是第一次插入的节点 if (root == null) { root = newNode; return; } else { while (true) { //父节点指向当前节点 parent = current; //如果当前节点指向的数据,比插入的要大,则向左走 if (value < current.data) { current = current.leftChild; if (current == null) { parent.leftChild = newNode; return; } } else { current = current.rightChild; if (current == null) { parent.rightChild = newNode; return; } } } } } /** * 查找节点 */ public Node find(int value) { //引用当前节点,从根节点开始 Node current = root; //只要查找的值,不等于当前节点的值 while (current.data != value) { //比较查找值,与当前节点值的大小 if (current.data > value) { current = current.leftChild; } else { current = current.rightChild; } //如果查找不到 if (current == null) { return null; } } return current; } /** * 删除节点 */ public void delete(int value) { } }
package cn.jxufe.ch07_tree; public class TestTree { public static void main(String[] args) { Tree tree = new Tree(); tree.insert(10, "zhangsan"); tree.insert(20, "lisi"); tree.insert(3, "wangwu"); tree.insert(14, "zhaoliu"); tree.insert(76, "zhouqi"); System.out.println(tree.root.data); System.out.println(tree.root.leftChild.data); System.out.println(tree.root.rightChild.data); System.out.println(tree.root.rightChild.leftChild.data); System.out.println(tree.root.rightChild.rightChild.data); Node node = tree.find(20); System.out.println(node.data + "," + node.sdata); System.out.println(node.rightChild.data + "," + node.rightChild.sdata); } }
2.2遍历二叉树
package cn.jxufe.ch07_tree; /** * 二叉树节点 */ public class Node { //数据项 public int data; public String sdata; public Node leftChild; public Node rightChild; public Node(int data,String sdata) { this.data = data; this.sdata =sdata; } }
package cn.jxufe.ch07_tree; /** * 二叉树 */ public class Tree { //根节点 public Node root; /** * 插入节点 */ public void insert(int value, String sdata) { //封装节点 Node newNode = new Node(value, sdata); //引用当前节点 Node current = root; //引用父节点 Node parent; //如果root为null,也就是第一次插入的节点 if (root == null) { root = newNode; return; } else { while (true) { //父节点指向当前节点 parent = current; //如果当前节点指向的数据,比插入的要大,则向左走 if (value < current.data) { current = current.leftChild; if (current == null) { parent.leftChild = newNode; return; } } else { current = current.rightChild; if (current == null) { parent.rightChild = newNode; return; } } } } } /** * 查找节点 */ public Node find(int value) { //引用当前节点,从根节点开始 Node current = root; //只要查找的值,不等于当前节点的值 while (current.data != value) { //比较查找值,与当前节点值的大小 if (current.data > value) { current = current.leftChild; } else { current = current.rightChild; } //如果查找不到 if (current == null) { return null; } } return current; } /** * 删除节点 */ public void delete(int value) { } /** * 前序遍历 */ public void frontOrder(Node localNode) { if (localNode != null) { //访问根节点 System.out.print(localNode.data + ":" + localNode.sdata + " "); //前序遍历左子树 frontOrder(localNode.leftChild); //前序遍历右子树 frontOrder(localNode.rightChild); } } /** * 中序遍历 */ public void inOrder(Node localNode) { if (localNode != null) { //中序遍历左子树 inOrder(localNode.leftChild); //访问根节点 System.out.print(localNode.data + "," + localNode.sdata + " "); //中序遍历右子树 inOrder(localNode.rightChild); } } /** * 后序遍历 */ public void afterOrder(Node localNode) { if (localNode != null) { //后序遍历左子树 afterOrder(localNode.leftChild); //后序遍历右子树 afterOrder(localNode.rightChild); //访问根节点 System.out.print(localNode.data + "," + localNode.sdata + " "); } } }
package cn.jxufe.ch07_tree; public class TestTree { public static void main(String[] args) { Tree tree = new Tree(); tree.insert(10, "zhangsan"); tree.insert(20, "lisi"); tree.insert(3, "wangwu"); tree.insert(14, "zhaoliu"); tree.insert(76, "zhouqi"); tree.insert(13, "zhuba"); System.out.println("前序遍历:"); tree.frontOrder(tree.root); System.out.println(); System.out.println("中序遍历:"); tree.inOrder(tree.root); System.out.println(); System.out.println("后序遍历:"); tree.afterOrder(tree.root); } }
2.3删除二叉树节点
package interview; public class Tree { private Node root; public void insertNode(int data, String sdata) { Node newNode = new Node(data, sdata); // 引用当前节点 Node current = root; Node parent; // 如果root为null,也就是第一次插入 if (root == null) { root = newNode; } else { while (true) { parent = current; // 如果当前节点指向的数据,比插入的节点数据要大,则向左走 if (data < current.data) { current = current.leftChildNode; if (current == null) { parent.leftChildNode = newNode; return; } } else { current = current.rightChildNode; if (current == null) { parent.rightChildNode = newNode; return; } } } } } public Node findNode(int value) { Node current = root; while (current.data != value) { if (current.data > value) { current = current.leftChildNode; } else { current = current.rightChildNode; } if (current == null) { return null; } } return current; } public void fontOrder(Node root) { if (root != null) { System.out.println(root.data); fontOrder(root.leftChildNode); fontOrder(root.rightChildNode); } } public Node getSuccessor(Node delNode) { Node successor = delNode; Node successorParent = delNode; Node current = delNode.rightChildNode; while (current != null) { successorParent = successor; successor = current; current = current.leftChildNode; } if(successor != delNode.rightChildNode) { successorParent.leftChildNode = successor.rightChildNode; successor.rightChildNode = delNode.rightChildNode; } return successor; } public boolean deleteNode(int value) { // 引用当前节点为根节点 Node current = root; // 引用当前节点的父节点 Node parent = root; // 是否为左子树 boolean isLeftchild = true; // 查找 while (current.data != value) { parent = current; // 比较 if (current.data > value) { current = current.leftChildNode; isLeftchild = true; } else { current = current.rightChildNode; isLeftchild = false; } if (current == null) { return false; } } // 删除 if (current.leftChildNode == null && current.rightChildNode == null) {// 1. 删除的节点为叶子节点 if (current == root) { root = null; } else if (isLeftchild) {// 如果它是父节点的左子节点 parent.leftChildNode = null; } else { parent.rightChildNode = null; } } else if (current.rightChildNode == null) { // 2. 该节点有一个子节点,且为左子节点 if (current == root) { root = current.leftChildNode; } else if (isLeftchild) { parent.leftChildNode = current.leftChildNode; } else { parent.rightChildNode = current.leftChildNode; } } else if (current.leftChildNode == null) { // 该节点只有一个节点,且为右子节点 if (current == root) { root = current.rightChildNode; } else if (isLeftchild) { parent.leftChildNode = current.rightChildNode; } else { parent.rightChildNode = current.rightChildNode; } }else { Node successor = getSuccessor(current);// 查找中序后继节点 if(current == root) { // 以下是完成替换功能 root = successor; }else if(isLeftchild) { parent.leftChildNode = successor; }else { parent.rightChildNode = successor; } successor.leftChildNode = current.leftChildNode; } return true; } public static void main(String[] args) { Tree tree = new Tree(); tree.insertNode(10, "zhangsan"); tree.insertNode(20, "lisi"); tree.insertNode(3, "wangwu"); tree.insertNode(14, "zhaoliu"); tree.insertNode(76, "zhouqi"); tree.insertNode(5, "niaho"); // System.out.println(tree.root.data); // System.out.println(tree.root.leftChildNode.data); // System.out.println(tree.root.rightChildNode.data); // System.out.println(tree.root.rightChildNode.leftChildNode.data); // System.out.println(tree.root.rightChildNode.rightChildNode.data); // Node node = tree.findNode(20); // System.out.println(node.data + "," + node.sdata); // System.out.println(node.rightChildNode.data + "," + // node.rightChildNode.sdata); tree.fontOrder(tree.root); tree.deleteNode(3); System.out.println("--------------------"); tree.fontOrder(tree.root); tree.deleteNode(20); System.out.println("------------------------"); tree.fontOrder(tree.root); } } class Node { // 数据域 public int data; public String sdata; // 指针域 public Node leftChildNode; public Node rightChildNode; public Node(int data, String sdata) { // TODO Auto-generated constructor stub this.data = data; this.sdata = sdata; } }
2.4根据中序和后序,求前序遍历
package exam; import java.util.Arrays; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub // Scanner sc = new Scanner(System.in); // String in = sc.nextLine(); String in = "dgbaechf"; char[] inArray = in.toCharArray(); // String last = sc.nextLine(); String last = "gbdehfca"; char[] lastArray = last.toCharArray(); // System.out.println(Arrays.toString(preArray)); // System.out.println(Arrays.toString(inArray)); Node node = buildTree(inArray, lastArray); frontOrder(node); } public static Node buildTree(char[] inorder, char[] postorder) { if (inorder == null || postorder == null || inorder.length == 0 || postorder.length == 0) { return null; } // 将后序遍历的最后一个节点取出为根 Node root = new Node(postorder[postorder.length - 1]); int i = 0;// 记录中序遍历根的位置 for (; i < inorder.length; i++) { if (postorder[postorder.length - 1] == inorder[i]) { break; } } // 构造左子树 char[] leftIn = Arrays.copyOfRange(inorder, 0, i); char[] leftPost = Arrays.copyOfRange(postorder, 0, i); // 构造右子树 char[] rightIn = Arrays.copyOfRange(inorder, i + 1, inorder.length); char[] rightPost = Arrays.copyOfRange(postorder, i, postorder.length - 1); // 左子树 root.leftChild = buildTree(leftIn, leftPost); // 右子树 root.rightChild = buildTree(rightIn, rightPost); return root; } /** * 前序遍历 */ public static void frontOrder(Node localNode) { if (localNode != null) { // 访问根节点 System.out.print(localNode.data + " "); // 前序遍历左子树 frontOrder(localNode.leftChild); // 前序遍历右子树 frontOrder(localNode.rightChild); } } } /** * 二叉树节点 */ class Node { // 数据项 public char data; public Node leftChild; public Node rightChild; public Node(char data) { this.data = data; } }
2.5二叉树高度
package datastruct.t04tree; /** * 二叉树节点 * */ public class Node { public int data; public Node leftChild; public Node rightChild; public Node(int data) { this.data = data; } public void setLeftChild(Node leftChild) { this.leftChild = leftChild; } public void setRightChild(Node rightChild) { this.rightChild = rightChild; } public static Node createNode(int data) { Node node = new Node(data); node.leftChild = node.rightChild = null; return node; } public static void setChild(Node node, Node leftChild, Node rightChild) { node.setLeftChild(leftChild); node.setRightChild(rightChild); } }
package datastruct.t04tree; public class BiTree { public static int getTreeHeight(Node root) { if (root == null) { return 0; } else { int leftHeight = getTreeHeight(root.leftChild); int rightHeight = getTreeHeight(root.rightChild); return Math.max(leftHeight, rightHeight) + 1; } } public static void main(String[] args) { // 快速构建一棵二叉树 Node root = Node.createNode(1); Node node2 = Node.createNode(2); Node node3 = Node.createNode(3); Node node4 = Node.createNode(4); Node node5 = Node.createNode(5); Node node6 = Node.createNode(6); Node node7 = Node.createNode(7); Node node8 = Node.createNode(8); Node.setChild(root, node2, node3); Node.setChild(node2, node4, node5); Node.setChild(node3, null, node7); Node.setChild(node4, null, node8); Node.setChild(node5, node6, null); // 树的高度 int height = getTreeHeight(root); System.out.print("树的高度为:"); System.out.println(height); } }
2.6表达式树的输出与求值
表达式树的特征:叶节点是运算数,非叶节点一定是运算符
输入格式:
第一行给出节点的个数N,每个节点的编号为0 ~ N-1
接下来N行每行分别给出:
该节点的编号、该节点的操作数/操作符、该节点的左孩子编号、右孩子编号(-1表示NULL)
输出格式:
第一行输出该表达式树的中缀表达式,该用括号的地方需要用括号括起来。
第二行输出该表达式树的前缀表达式。
第二行输出该表达式树的后缀表达式。
第四行输出该表达式树的计算结果,保留两位小数。
样例输入:
11 0 - 1 2 1 + 3 4 2 / 5 6 3 4 -1 -1 4 * 7 8 5 6 -1 -1 6 3 -1 -1 7 1 -1 -1 8 - 9 10 9 5 -1 -1 10 2 -1 -1
样例输出:
(4+(1*(5-2)))-(6/3) - + 4 * 1 - 5 2 / 6 3 4 1 5 2 - * + 6 3 / - 5.00
package datastruct.t04tree.exptree; public class Node { char data; Node leftChild; Node rightChild; }
package datastruct.t04tree.exptree; import java.util.Scanner; public class ExpTree { // 中缀表达式 public static void inOrder(Node root, int layer) { if (root == null) return; if (root.leftChild == null && root.rightChild == null) { // 叶结点是操作数,直接输出,不加括号 System.out.print(root.data + " "); } else { // 非叶节点是操作符,需加括号(第0层根节点除外) if (layer > 0) { System.out.print("("); } inOrder(root.leftChild, layer + 1); System.out.print(root.data + " "); inOrder(root.rightChild, layer + 1); if (layer > 0) { System.out.print(")"); } } } // 前缀表达式 public static void preOrder(Node root) { if (root == null) return; System.out.print(root.data + " "); preOrder(root.leftChild); preOrder(root.rightChild); } // 后缀表达式 public static void postOrder(Node root) { if (root == null) return; postOrder(root.leftChild); postOrder(root.rightChild); System.out.print(root.data + " "); } public static double getExpTree(Node root) { if (root == null) { return 0; } if (root.leftChild == null && root.rightChild == null) { // 叶节点,节点存放的是 操作数 return root.data - '0'; // 将字符转换成数字 } // 非叶结点,节点存放的是 操作符 double a = getExpTree(root.leftChild); double b = getExpTree(root.rightChild); return cal(a, b, root.data); } public static double cal(double a, double b, char op) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: return 0; } } public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("请输入节点的个数"); int N = input.nextInt(); Node[] nodes = new Node[N]; for (int i = 0; i < N; i++) { nodes[i] = new Node(); } System.out.println("请输入index,data,l,r"); for (int i = 0; i < N; i++) { int index = input.nextInt(); char data = input.next().charAt(0); int l = input.nextInt(); int r = input.nextInt(); nodes[index].data = data; nodes[index].leftChild = (l != -1 ? nodes[l] : null); nodes[index].rightChild = (r != -1 ? nodes[r] : null); } Node root = nodes[0]; inOrder(root, 0); System.out.println(); preOrder(root); System.out.println(); postOrder(root); System.out.println(); double value = getExpTree(root); System.out.println(value); } }
2.7求二叉树指定节点所在层数(假设根节点的层数为1)
1.方法1
package datastruct.t04tree.layer; class Node { int data; Node leftChild; Node rightChild; public Node(int data) { this.data = data; } public void setChild(Node leftChild, Node rightChild) { this.leftChild = leftChild; this.rightChild = rightChild; } } public class NodeLayer { static int layer = 0; static boolean flag = false;// flag标记可用于提前快速结束递归的执行 public static void getNodeLayer(Node root, int value) { if (root == null) return; if (flag) return; layer++; if (root.data == value) { System.out.println(layer); flag = true; return; } getNodeLayer(root.leftChild, value); getNodeLayer(root.rightChild, value); layer--; } public static void main(String[] args) { Node root = new Node(1); Node node2 = new Node(2); Node node3 = new Node(3); Node node4 = new Node(4); Node node5 = new Node(5); Node node6 = new Node(6); Node node7 = new Node(7); Node node8 = new Node(8); root.setChild(node2, node3); node2.setChild(node4, node5); node3.setChild(null, node6); node5.setChild(node7, null); node7.setChild(null, node8); int value = 7; getNodeLayer(root, value); } }
2.方法2
package datastruct.t04tree.layer; class Node { int data; Node leftChild; Node rightChild; public Node(int data) { this.data = data; } public void setChild(Node leftChild, Node rightChild) { this.leftChild = leftChild; this.rightChild = rightChild; } } public class NodeLayer { static boolean flag = false; public static void getNodeLayer(Node root, int value, int layer) { if (root == null) return; if (flag) return; if (root.data == value) { System.out.println(layer); flag = true; return; } getNodeLayer(root.leftChild, value, layer + 1); getNodeLayer(root.rightChild, value, layer + 1); } public static void main(String[] args) { Node root = new Node(1); Node node2 = new Node(2); Node node3 = new Node(3); Node node4 = new Node(4); Node node5 = new Node(5); Node node6 = new Node(6); Node node7 = new Node(7); Node node8 = new Node(8); root.setChild(node2, node3); node2.setChild(node4, node5); node3.setChild(null, node6); node5.setChild(node7, null); node7.setChild(null, node8); int value = 7; getNodeLayer(root, value, 1); } }
2.8求某节点到根节点的路径
对于如下二叉树,节点 7 位于第 4 层,其到跟节点的路径为 1 2 5 7
package datastruct.t04tree.path; import java.util.Stack; class Node { int data; Node leftChild; Node rightChild; public Node(int data) { this.data = data; } public void setChild(Node leftChild, Node rightChild) { this.leftChild = leftChild; this.rightChild = rightChild; } } public class TreePath { static Stack<Integer> path = new Stack<>(); static boolean flag = false; public static void getNodePath(Node root, int value) { if (root == null) return; if (flag) return; path.add(root.data); if (root.data == value) { for (Integer integer : path) { System.out.print(integer + " "); } flag = true; return; } getNodePath(root.leftChild, value); getNodePath(root.rightChild, value); path.pop(); } public static void main(String[] args) { Node root = new Node(1); Node node2 = new Node(2); Node node3 = new Node(3); Node node4 = new Node(4); Node node5 = new Node(5); Node node6 = new Node(6); Node node7 = new Node(7); Node node8 = new Node(8); root.setChild(node2, node3); node2.setChild(node4, node5); node3.setChild(null, node6); node5.setChild(node7, null); node7.setChild(null, node8); int value = 7; getNodePath(root, value); } }
2.9全排列问题
输出数字1~N所能组成的所有全排列
package datastruct.t04tree.permutation; import java.util.Stack; public class Permutation { public static int MAXN = 10; static boolean[] isUsed = new boolean[MAXN]; static Stack<Integer> nums = new Stack<>(); static int N; /** * @param index * 表示第几层 */ public static void DFS(int index) { if (index >= N) { for (Integer i : nums) System.out.print(i + " "); System.out.println(); return; } for (int i = 1; i <= N; i++) { if (isUsed[i]) continue; nums.push(i); isUsed[i] = true; DFS(index + 1); nums.pop(); isUsed[i] = false; } } public static void main(String[] args) { N = 3; DFS(0);// 从第0层开始搜索 } }
3.红黑树
4.hash表
4.1直接将关键字作为索引
package ch15; public class Info { private int key; private String name; public Info(int key, String name) { // TODO Auto-generated constructor stub this.key = key; this.name = name; } public int getKey() { return key; } public void setKey(int key) { this.key = key; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package ch15; public class HashTable { private Info[] arr; public HashTable() { // TODO Auto-generated constructor stub arr = new Info[100]; } public HashTable(int maxSize) { arr = new Info[maxSize]; } public void insert(Info info) { arr[info.getKey()] = info; } public Info find(int key) { return arr[key]; } }
package ch15; public class TestHashTable { public static void main(String[] args) { HashTable hTable = new HashTable(); hTable.insert(new Info(10, "张三")); hTable.insert(new Info(15, "李四")); System.out.println(hTable.find(15).getName()); } }
4.2将单词转化为索引
package ch15; public class Info { private String key; private String name; public Info(String key, String name) { // TODO Auto-generated constructor stub this.key = key; this.name = name; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package ch15; public class HashTable { private Info[] arr; public HashTable() { // TODO Auto-generated constructor stub arr = new Info[100]; } public HashTable(int maxSize) { arr = new Info[maxSize]; } public void insert(Info info) { arr[hashCode(info.getKey())] = info; } public Info find(String key) { return arr[hashCode(key)]; } public int hashCode(String key) { int hashValue = 0; for (int i = key.length() - 1; i >= 0; i--) { int letter = key.charAt(i) - 96; hashValue += letter; } return hashValue; } }
package ch15; public class TestHashTable { public static void main(String[] args) { HashTable hTable = new HashTable(); hTable.insert(new Info("zhangsan", "张三")); hTable.insert(new Info("lisi", "李四")); System.out.println(hTable.find("zhangsan").getName()); } }
以上方法也会存在一定的问题,当hashcode相同的时候。
package ch15; public class TestHashTable { public static void main(String[] args) { HashTable hTable = new HashTable(); hTable.insert(new Info("abc", "张三")); hTable.insert(new Info("bca", "李四")); System.out.println(hTable.find("abc").getName()); System.out.println(hTable.find("bca").getName()); } }
我们用幂函数的方式去重写hashcode
public int hashCode(String key) { int hashValue = 0; int pow27 = 1; for (int i = key.length() - 1; i >= 0; i--) { int letter = key.charAt(i) - 96; hashValue += letter * pow27; pow27 *= 27; } return hashValue; }
package ch15; public class TestHashTable { public static void main(String[] args) { HashTable hTable = new HashTable(); hTable.insert(new Info("abc", "张三")); hTable.insert(new Info("bca", "李四")); System.out.println(hTable.find("abc").getName()); System.out.println(hTable.find("bca").getName()); } }
此时可以解决上面的问题,但是浪费太多内存了,因为字符串如果很长,数组容易越界或者内存溢出,因此需要进行取模运算。
public int hashCode(String key) { BigInteger hashValue = new BigInteger("0"); BigInteger pow27 = new BigInteger("1"); for (int i = key.length() - 1; i >= 0; i--) { int letter = key.charAt(i) - 96; BigInteger letterB = new BigInteger(String.valueOf(letter)); hashValue = hashValue.add(letterB.multiply(pow27)); pow27 = pow27.multiply(new BigInteger(String.valueOf(27))); } return hashValue.mod(new BigInteger(String.valueOf(key.length()))).intValue(); }