树的主要算法有插入,查找,显示,遍历,删除,其中显示和删除略微复杂。

  1. package chap08.tree;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.util.Stack;
  7.  
  8. class Node {
  9.  
  10. public int iData;
  11. public double dData;
  12.  
  13. public Node leftChild;
  14. public Node rightChild;
  15.  
  16. public void displayNode() {
  17. System.out.print("{" + iData + ", " + dData + "}");
  18. }
  19. }
  20.  
  21. class Tree {
  22.  
  23. // first node of tree
  24. private Node root;
  25.  
  26. public Tree() {
  27.  
  28. root = null;
  29. }
  30.  
  31. /*
  32. * 查找
  33. */
  34. public Node find(int key) {
  35.  
  36. // (assumes non-empty tree)
  37. Node current = root; // start at root
  38.  
  39. while (current.iData != key) // while no match,
  40. {
  41. if (key < current.iData) {
  42. current = current.leftChild;
  43. }
  44. else {
  45. current = current.rightChild;
  46. }
  47. if (current == null) {
  48. return null;
  49. }
  50. }
  51. return current; // found it
  52. }
  53.  
  54. /*
  55. * 插入
  56. */
  57. public void insert(int id, double dd) {
  58.  
  59. Node newNode = new Node(); // make new node
  60. newNode.iData = id; // insert data
  61. newNode.dData = dd;
  62.  
  63. if (root == null) { // no node in root
  64. root = newNode;
  65. }
  66. else // root occupied
  67. {
  68. Node current = root; // start at root
  69. Node parent;
  70.  
  71. while (true) // (exits internally)
  72. {
  73. parent = current;
  74. if (id < current.iData) {
  75. current = current.leftChild;
  76. if (current == null) {
  77. // insert on left
  78. parent.leftChild = newNode;
  79. return;
  80. }
  81. }
  82. else {
  83. current = current.rightChild;
  84. if (current == null) {
  85. // insert on right
  86. parent.rightChild = newNode;
  87. return;
  88. }
  89. }
  90. }
  91. }
  92. }
  93.  
  94. /*
  95. * 删除
  96. */
  97. public boolean delete(int key)
  98. {
  99. // (assumes non-empty list)
  100. Node current = root;
  101. Node parent = root;
  102. boolean isLeftChild = true;
  103.  
  104. // search for node
  105. while (current.iData != key)
  106. {
  107. parent = current;
  108. if (key < current.iData) // go left?
  109. {
  110. isLeftChild = true;
  111. current = current.leftChild;
  112. }
  113. else
  114. {
  115. isLeftChild = false;
  116. current = current.rightChild;
  117. }
  118. if (current == null) // end of the line,
  119. return false; // didn't find it
  120. }
  121.  
  122. // if no children, simply delete it
  123. if (current.leftChild == null && current.rightChild == null) {
  124. if (current == root) {
  125. root = null;
  126. }
  127. else if (isLeftChild) {
  128. parent.leftChild = null; // disconnect
  129. }
  130. else {
  131. // from parent
  132. parent.rightChild = null;
  133. }
  134. }
  135.  
  136. // if no right child, replace with left subtree
  137. else if (current.rightChild == null) {
  138. if (current == root) {
  139. root = current.leftChild;
  140. }
  141. else if (isLeftChild) {
  142. parent.leftChild = current.leftChild;
  143. }
  144. else {
  145. parent.rightChild = current.leftChild;
  146. }
  147. }
  148.  
  149. // if no left child, replace with right subtree
  150. else if (current.leftChild == null)
  151. if (current == root)
  152. root = current.rightChild;
  153. else if (isLeftChild)
  154. parent.leftChild = current.rightChild;
  155. else
  156. parent.rightChild = current.rightChild;
  157.  
  158. // 有两个孩子,则用中序后继替代
  159. else
  160. {
  161. // get successor of node to delete (current)
  162. Node successor = getSuccessor(current);
  163.  
  164. // connect parent of current to successor instead
  165. if (current == root) {
  166. root = successor;
  167. }
  168. else if (isLeftChild) {
  169. parent.leftChild = successor;
  170. }
  171. else {
  172. parent.rightChild = successor;
  173. }
  174.  
  175. // connect successor to current's left child
  176. successor.leftChild = current.leftChild;
  177. }
  178.  
  179. return true;
  180. }
  181.  
  182. /*
  183. * 获取后继
  184. * 返回具有倒数第二高的值的节点
  185. * 找到右孩子,然后右孩子的左子孙
  186. */
  187. private Node getSuccessor(Node delNode) {
  188.  
  189. Node successorParent = delNode;
  190. Node successor = delNode;
  191.  
  192. // go to right child
  193. Node current = delNode.rightChild;
  194.  
  195. while (current != null) {
  196. successorParent = successor;
  197. successor = current;
  198. // go to left child
  199. current = current.leftChild;
  200. }
  201.  
  202. // if successor not right child
  203. if (successor != delNode.rightChild) {
  204.  
  205. // make connections
  206. successorParent.leftChild = successor.rightChild;
  207. successor.rightChild = delNode.rightChild;
  208. }
  209. return successor;
  210. }
  211.  
  212. public void traverse(int traverseType) {
  213. switch (traverseType) {
  214. case 1:
  215. System.out.print("\nPreorder traversal: ");
  216. preOrder(root);
  217. break;
  218. case 2:
  219. System.out.print("\nInorder traversal: ");
  220. inOrder(root);
  221. break;
  222. case 3:
  223. System.out.print("\nPostorder traversal: ");
  224. postOrder(root);
  225. break;
  226. }
  227. System.out.println();
  228. }
  229.  
  230. /*
  231. * 先序遍历
  232. */
  233. private void preOrder(Node localRoot) {
  234. if (localRoot != null) {
  235. System.out.print(localRoot.iData + " ");
  236. preOrder(localRoot.leftChild);
  237. preOrder(localRoot.rightChild);
  238. }
  239. }
  240.  
  241. /*
  242. * 中序遍历
  243. */
  244. private void inOrder(Node localRoot) {
  245. if (localRoot != null) {
  246. inOrder(localRoot.leftChild);
  247. System.out.print(localRoot.iData + " ");
  248. inOrder(localRoot.rightChild);
  249. }
  250. }
  251.  
  252. /*
  253. * 后序遍历
  254. */
  255. private void postOrder(Node localRoot) {
  256. if (localRoot != null) {
  257. postOrder(localRoot.leftChild);
  258. postOrder(localRoot.rightChild);
  259. System.out.print(localRoot.iData + " ");
  260. }
  261. }
  262.  
  263. /*
  264. * 在控制台打印显示树
  265. *
  266. */
  267. public void displayTree() {
  268.  
  269. // 全局栈,初始放入树的根节点
  270. Stack globalStack = new Stack();
  271. globalStack.push(root);
  272.  
  273. // 打印空格的数量
  274. int nBlanks = 32;
  275.  
  276. // 是否为空的标识
  277. boolean isRowEmpty = false;
  278.  
  279. while (isRowEmpty == false) {
  280.  
  281. // 本地栈
  282. Stack localStack = new Stack();
  283.  
  284. // 设置标识为空,后边再根据实际情况判断其是否不为空
  285. isRowEmpty = true;
  286.  
  287. // 打印一定数量的空格,为了将节点 放置在适当的位置以满足视觉效果上树的形状
  288. for (int j = 0; j < nBlanks; j++) {
  289. System.out.print(' ');
  290. }
  291.  
  292. while (globalStack.isEmpty() == false) {
  293.  
  294. // 当标识不为空时,从全局栈弹出栈顶节点
  295. Node temp = (Node) globalStack.pop();
  296.  
  297. if (temp != null) {
  298. // 如果当前从全局栈弹出的栈顶元素 不为空,则打印当前节点数值,同时将其左右孩子节点放入本地栈
  299. System.out.print(temp.iData);
  300. // 先放左孩子,后方右孩子,后边转移到全局栈后,可以反序,从而保证左孩子在右孩子顶端
  301. localStack.push(temp.leftChild);
  302. localStack.push(temp.rightChild);
  303.  
  304. // 如果当前全局栈弹出的节点有左孩子或右孩子
  305. if (temp.leftChild != null || temp.rightChild != null) {
  306. // 设置标识不为空
  307. isRowEmpty = false;
  308. }
  309. }
  310. else {
  311. // 如果当前从全局栈弹出的栈顶元素 为空,则打印"--"替代节点数值,同时将两个空值放入本地栈
  312. System.out.print("-");
  313. localStack.push(null);
  314. localStack.push(null);
  315. }
  316.  
  317. for (int j = 0; j < nBlanks * 2 - 1; j++) {
  318. System.out.print(' ');
  319. }
  320. }
  321.  
  322. System.out.println();
  323. System.out.println();
  324.  
  325. nBlanks /= 2;
  326.  
  327. while (localStack.isEmpty() == false) {
  328. // 将本地栈的节点放入全局栈,进行反序,从而保证先处理左孩子
  329. globalStack.push(localStack.pop());
  330. }
  331. }
  332. }
  333. }
  334.  
  335. class TreeApp {
  336. public static void main(String[] args) throws IOException {
  337. int value;
  338. Tree theTree = new Tree();
  339.  
  340. theTree.insert(50, 1.5);
  341. theTree.insert(25, 1.2);
  342. theTree.insert(75, 1.7);
  343. theTree.insert(12, 1.5);
  344. theTree.insert(37, 1.2);
  345. theTree.insert(43, 1.7);
  346. theTree.insert(30, 1.5);
  347. theTree.insert(33, 1.2);
  348. theTree.insert(87, 1.7);
  349. theTree.insert(93, 1.5);
  350.  
  351. while (true) {
  352. System.out.print("Enter first letter of show, insert, find, delete, or traverse: ");
  353.  
  354. int choice = getChar();
  355. switch (choice) {
  356. case 's':
  357. theTree.displayTree();
  358. break;
  359. case 'i':
  360. System.out.print("Enter value to insert: ");
  361. value = getInt();
  362. theTree.insert(value, value + 0.9);
  363. break;
  364. case 'f':
  365. System.out.print("Enter value to find: ");
  366. value = getInt();
  367. Node found = theTree.find(value);
  368. if (found != null) {
  369. System.out.print("Found: ");
  370. found.displayNode();
  371. System.out.print("\n");
  372. }
  373. else {
  374. System.out.print("Could not find ");
  375. }
  376. System.out.print(value + '\n');
  377. break;
  378. case 'd':
  379. System.out.print("Enter value to delete: ");
  380. value = getInt();
  381. boolean didDelete = theTree.delete(value);
  382. if (didDelete) {
  383. System.out.print("Deleted " + value + '\n');
  384. }
  385. else {
  386. System.out.print("Could not delete ");
  387. }
  388. System.out.print(value + '\n');
  389. break;
  390. case 't':
  391. System.out.print("Enter type 1, 2 or 3: ");
  392. value = getInt();
  393. theTree.traverse(value);
  394. break;
  395. default:
  396. System.out.print("Invalid entry\n");
  397. }
  398. }
  399. }
  400.  
  401. /*
  402. * 获取输入
  403. */
  404. public static String getString() throws IOException {
  405. InputStreamReader isr = new InputStreamReader(System.in);
  406. BufferedReader br = new BufferedReader(isr);
  407.  
  408. String s = br.readLine();
  409. return s;
  410. }
  411.  
  412. public static char getChar() throws IOException {
  413. String s = getString();
  414. return s.charAt(0);
  415. }
  416.  
  417. public static int getInt() throws IOException {
  418. String s = getString();
  419. return Integer.parseInt(s);
  420. }
  421. }

Java数据结构与算法(20) - ch08树的更多相关文章

  1. Java数据结构和算法(七)--AVL树

    在上篇博客中,学习了二分搜索树:Java数据结构和算法(六)--二叉树,但是二分搜索树本身存在一个问题: 如果现在插入的数据为1,2,3,4,5,6,这样有序的数据,或者是逆序 这种情况下的二分搜索树 ...

  2. Java数据结构和算法 - 什么是2-3-4树

    Q1: 什么是2-3-4树? A1: 在介绍2-3-4树之前,我们先说明二叉树和多叉树的概念. 二叉树:每个节点有一个数据项,最多有两个子节点. 多叉树:(multiway tree)允许每个节点有更 ...

  3. Java数据结构和算法(七)B+ 树

    Java数据结构和算法(七)B+ 树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 我们都知道二叉查找树的查找的时间复杂度是 ...

  4. Java数据结构和算法(一)树

    Java数据结构和算法(一)树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 前面讲到的链表.栈和队列都是一对一的线性结构, ...

  5. Java数据结构和算法(四)赫夫曼树

    Java数据结构和算法(四)赫夫曼树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 赫夫曼树又称为最优二叉树,赫夫曼树的一个 ...

  6. java数据结构和算法07(2-3-4树)

    上一篇我们大概了解了红黑树到底是个什么鬼,这篇我们可以看看另外一种树-----2-3-4树,看这个树的名字就觉得很奇怪.... 我们首先要知道这里的2.3.4指的是任意一个节点拥有的子节点个数,所以我 ...

  7. Java数据结构和算法 - 二叉树

    前言 数据结构可划分为线性结构.树型结构和图型结构三大类.前面几篇讨论了数组.栈和队列.链表都是线性结构.树型结构中每个结点只允许有一个直接前驱结点,但允许有一个以上直接后驱结点.树型结构有树和二叉树 ...

  8. Java数据结构和算法 - 递归

    三角数字 Q: 什么是三角数字? A: 据说一群在毕达哥拉斯领导下工作的古希腊的数学家,发现了在数学序列1,3,6,10,15,21,……中有一种奇特的联系.这个数列中的第N项是由第N-1项加N得到的 ...

  9. Java数据结构与算法 - 外部存储

    Q: 什么是外部存储? A: 外部存储特指某类磁盘系统,例如在大多数台式电脑或服务器中的硬盘. Q: 如何访问外部存储? A: 我们所学的数据结构都是假设数据存储在内存中,但是,在很多情况下要处理的数 ...

随机推荐

  1. 采用Java语言如何实现高速文件复制?

    今天review代码也看到了"大神"用老方法来实现文件拷贝.今天归结一下使用Java语言怎样实现高速文件复制: 代码1--使用文件通道的方式: import java.io.Fil ...

  2. cocos2dx环境配置和打包

    安装软件准备就绪: vs2012 cocos2d-x-2.2.1 adt-bundle-windows-x86_64-20121030 android-ndk-r9c-windows-x86_64 j ...

  3. UNITY3D MAC版本号破解

    首先,解释一下.是公司做开发建议去购买正版. 之前网上也有非常多人贴出了破解方法,有些也是能够的.可是大多数解说不太具体,在这里贴出相对具体点的教程.本人亲測成功(測试版本Unity4.0.1 mac ...

  4. CMSIS标准

    CMSIS 标准(Cortex Microcontroller Software Interface Standard) ,翻译过来是"ARM Cortex™ 微控制器软件接口标准" ...

  5. IOS开发——手动设置屏幕旋转

    在移动开发过程.您可能需要跨越看看你的手机.有可能是所有的接口必须跨越,有可能是一个交叉通过电话,当用户当,你的接口也希望他能跨越.还有可能的是,界面的一部分需要被侧向显示.视情况而定,有不同的方法来 ...

  6. PowerShell 批量导入/导出Active Directory

    PowerShell 批量导入/导出Active Directory         近期由于公司要求,须要导入20个供应商.20个客户到AD域中,刚開始手动添�了2个供应商,2个客户.可是感觉费时费 ...

  7. MemoryBarrier,Volatile

    使用MemoryBarrier,Volatile进行同步 上一节介绍了使用信号量进行同步,本节主要介绍一些非阻塞同步的方法.本节主要介绍MemoryBarrier,volatile,Interlock ...

  8. 跨容器Hybrid离线组件方案

    关键词:跨容器.Hybrid.离线 摘要:今天主要讨论的是离线组件跨容器方案,想了解在线页面如何跨webview容器,可以看 http://www.cnblogs.com/yexiaochai/p/5 ...

  9. 如何对 GIT 分支进行规划? (转)

    项目背景: 该项目是在2011年11月份使用Asp.net三层帮荷兰某个客户开发的机票预定系统 该客户主要是做中国与欧洲的旅行社业务,特别是最近两年由于中国的发展因此客户也越来越重视机票业务 于是他们 ...

  10. 一张图让你看清Java集合类(Java集合类的总结)

    如今关于Java集合类的文章非常多,可是我近期看到一个非常有意思图片,基本上把Java集合的整体框架都给展现出来了.非常直观. watermark/2/text/aHR0cDovL2Jsb2cuY3N ...