- 前言情景引入
- 一、哈希表是什么?
- 1.实例+代码
- 二、二叉树
- 1.树的引入
- 2.二叉树的遍历
前言情景引入
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址…),当输入该员工的id时,要求查找到该员工的所有信息.
要求:不使用数据库,尽量节省内存,速度越快越好=>哈希表(散列)
散列表(Hashtable,也叫哈希表),是根据关键码值(Keyvalue)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
1.实例+代码有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,名字,住址…),当输入该员工的id时,要求查找到该员工的所有信息.
要求: 1)不使用数据库,,速度越快越好=>哈希表(散列) 2)添加时,保证按照id从低到高插入 3)使用链表来实现哈希表,该链表不带表头[即:链表的第一个结点就存放雇员信息]
package com.JavaTest.Demo; import java.util.Scanner; public class HashTabDemo { public static void main(String[] args) { //创建哈希表 HashTab hashTab = new HashTab(7); String key = ""; Scanner scanner = new Scanner(System.in); while(true) { System.out.println("add: 添加雇员"); System.out.println("list: 显示雇员"); System.out.println("find: 查找雇员"); System.out.println("exit: 退出系统"); key = scanner.next(); switch (key) { case "add": System.out.println("输入id"); int id = scanner.nextInt(); System.out.println("输入名字"); String name = scanner.next(); Emp emp = new Emp(id, name); hashTab.add(emp); break; case "list": hashTab.list(); break; case "find": System.out.println("请输入要查找的id"); id = scanner.nextInt(); hashTab.findEmpById(id); break; case "exit": scanner.close(); System.exit(0); default: break; } } } } class HashTab { private EmplinkedList[] emplinkedListArray; private int size; //表示链表 public HashTab(int size) { this.size = size; emplinkedListArray = new EmplinkedList[size]; for(int i = 0; i < size; i++) { emplinkedListArray[i] = new EmplinkedList(); } } public void add(Emp emp) { int emplinkedListNO = hashFun(emp.id); emplinkedListArray[emplinkedListNO].add(emp); } //遍历 public void list() { for(int i = 0; i < size; i++) { emplinkedListArray[i].list(i); } } //根据id,查找雇员 public void findEmpById(int id) { int emplinkedListNO = hashFun(id); Emp emp = emplinkedListArray[emplinkedListNO].findEmpById(id); if(emp != null) { System.out.printf("在第%d条链表中找到 雇员 id = %dn", (emplinkedListNO + 1), id); }else{ System.out.println("在哈希表中,没有找到该雇员"); } } public int hashFun(int id) { return id % size; } } //表示一个雇员 class Emp { public int id; public String name; public Emp next; public Emp(int id, String name) { super(); this.id = id; this.name = name; } } class EmplinkedList { private Emp head; public void add(Emp emp) { if(head == null) { head = emp; return; } Emp curEmp = head; while(true) { if(curEmp.next == null) { break; } curEmp = curEmp.next; } curEmp.next = emp; } //遍历 public void list(int no) { if(head == null) { System.out.println("第 "+(no+1)+" 链表为空"); return; } System.out.print("第 "+(no+1)+" 链表的信息为"); Emp curEmp = head; //辅助指针 while(true) { System.out.printf(" => id=%d name=%st", curEmp.id, curEmp.name); if(curEmp.next == null) { break; } curEmp = curEmp.next; //后移 } System.out.println(); } public Emp findEmpById(int id) { //判断链表是否为空 if(head == null) { System.out.println("链表为空"); return null; } //辅助指针 Emp curEmp = head; while(true) { if(curEmp.id == id) { break; } if(curEmp.next == null) { curEmp = null; break; } curEmp = curEmp.next; } return curEmp; } }二、二叉树 1.树的引入
1、数组存储方式的分析
优点:通过下标方式访问元素,速度快。对于有序数组,还可使用二分查找提高检索速度。
缺点:如果要检索具体某个值,或者插入值(按一定顺序)会整体移动,效率较低
2、链式存储方式的分析
优点:在一定程度上对数组存储方式有优化(比如:插入一个数值节点,只需要将插入节点,链接到链表中即可,删除效率也很好)。
缺点:在进行检索时,效率仍然较低,比如(检索某个值,需要从头节点开始遍历)
3、树存储方式的分析
能提高数据存储,读取的效率,比如利用二叉排序树(BinarySortTree),既可以保证数据的检索速度,同时也可以保证数据的插入,删除,修改的速度。
思路:
1. 因为我们的二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除结点,而不能去判断当前这个结点是不是需要删除结点.
2. 如果当前结点的左子结点不为空,并且左子结点 就是要删除结点,就将this.left = null; 并且就返回(结束递归删除)
3. 如果当前结点的右子结点不为空,并且右子结点 就是要删除结点,就将this.right= null ;并且就返回(结束递归删除)
4. 如果第2和第3步没有删除结点,那么我们就需要向左子树进行递归删除
5. 如果第4步也没有删除结点,则应当向右子树进行递归删除.
代码如下(示例):
package com.JavaTest.Demo; public class BinaryTreeDemo { public static void main(String[] args) { BinaryTree binaryTree = new BinaryTree(); HeroNode root = new HeroNode(1, "宋江"); HeroNode node2 = new HeroNode(2, "吴用"); HeroNode node3 = new HeroNode(3, "卢俊义"); HeroNode node4 = new HeroNode(4, "林冲"); HeroNode node5 = new HeroNode(5, "关胜"); root.setLeft(node2); root.setRight(node3); node3.setRight(node4); node3.setLeft(node5); binaryTree.setRoot(root); System.out.println("前序遍历"); binaryTree.preOrder(); System.out.println("中序遍历"); binaryTree.infixOrder(); System.out.println("后序遍历"); binaryTree.postOrder(); System.out.println("后序遍历方式"); HeroNode resNode = binaryTree.postOrderSearch(5); if (resNode != null) { System.out.printf("找到了,信息为 no=%d name=%s", resNode.getNo(), resNode.getName()); } else { System.out.printf("没有找到 no = %d 的英雄", 5); } } } class BinaryTree { private HeroNode root; public void setRoot(HeroNode root) { this.root = root; } //前序遍历 public void preOrder() { if(this.root != null) { this.root.preOrder(); }else { System.out.println("二叉树为空,无法遍历"); } } //中序遍历 public void infixOrder() { if(this.root != null) { this.root.infixOrder(); }else { System.out.println("二叉树为空,无法遍历"); } } //后序遍历 public void postOrder() { if(this.root != null) { this.root.postOrder(); }else { System.out.println("二叉树为空,无法遍历"); } } //前序遍历 public HeroNode preOrderSearch(int no) { if(root != null) { return root.preOrderSearch(no); } else { return null; } } //中序遍历 public HeroNode infixOrderSearch(int no) { if(root != null) { return root.infixOrderSearch(no); }else { return null; } } //后序遍历 public HeroNode postOrderSearch(int no) { if(root != null) { return this.root.postOrderSearch(no); }else { return null; } } } class HeroNode { private int no; private String name; private HeroNode left; //默认null private HeroNode right; //默认null public HeroNode(int no, String name) { this.no = no; this.name = name; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public HeroNode getLeft() { return left; } public void setLeft(HeroNode left) { this.left = left; } public HeroNode getRight() { return right; } public void setRight(HeroNode right) { this.right = right; } public String toString() { return "Heronode [no=" + no + ", name=" + name + "]"; } //编写前序遍历的方法 public void preOrder() { System.out.println(this); if(this.left != null) { this.left.preOrder(); } if(this.right != null) { this.right.preOrder(); } } //中序遍历 public void infixOrder() { if(this.left != null) { this.left.infixOrder(); } System.out.println(this); if(this.right != null) { this.right.infixOrder(); } } //后序遍历 public void postOrder() { if(this.left != null) { this.left.postOrder(); } if(this.right != null) { this.right.postOrder(); } System.out.println(this); } public HeroNode preOrderSearch(int no) { System.out.println("进入前序遍历"); //比较当前结点是不是 if(this.no == no) { return this; } //1.则判断当前结点的左子节点是否为空,如果不为空,则递归前序查找 //2.如果左递归前序查找,找到结点,则返回 HeroNode resNode = null; if(this.left != null) { resNode = this.left.preOrderSearch(no); } if(resNode != null) { return resNode; } //1.左递归前序查找,找到结点,则返回,否继续判断, //2.当前的结点的右子节点是否为空,如果不空,则继续向右递归前序查找 if(this.right != null) { resNode = this.right.preOrderSearch(no); } return resNode; } //中序遍历查找 public HeroNode infixOrderSearch(int no) { HeroNode resNode = null; if(this.left != null) { resNode = this.left.infixOrderSearch(no); } if(resNode != null) { return resNode; } System.out.println("进入中序查找"); //如果找到,则返回,如果没有找到,就和当前结点比较,如果是则返回当前结点 if(this.no == no) { return this; } if(this.right != null) { resNode = this.right.infixOrderSearch(no); } return resNode; } //后序遍历查找 public HeroNode postOrderSearch(int no) { HeroNode resNode = null; if(this.left != null) { resNode = this.left.postOrderSearch(no); } if(resNode != null) { return resNode; } if(this.right != null) { resNode = this.right.postOrderSearch(no); } if(resNode != null) { return resNode; } System.out.println("进入后序查找"); if(this.no == no) { return this; } return resNode; } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)