算法与数据结构 (三) 二叉树的简单应用 二叉查找树,二叉堆排序
一? 二叉查找樹
二叉查找樹又叫二叉排序樹,是為了解決查找的效率問題。正常情況下查找一個元素,需要O(n)的代價,但是如果查找元素有順序,有序數組:可以用二分查找降低到 lgn 代價,但是有序鏈表的代價還是O(n) 因為,鏈表不支持隨機訪問,定位不到中間元素,從而不可以一次就排除掉一半元素。此時二叉查找樹的出現,完美解決了這個問題,左邊的全比根小,右邊的全比根大。所以理想狀態下也是一次淘汰一半元素(當然不理想,所以出現了紅黑樹和平衡二叉排序樹),一次淘汰一半(實際淘汰不了)和二分查找思路不謀而合。樹的簡單實現(包括查找,插入,刪除算法):
package tree.one;import tree.MyTree;import java.util.ArrayDeque; import java.util.Queue;public class FindTree {private FindTree left;private FindTree right;private int val;FindTree() {}FindTree(int val) {this.val = val;}//插入一個節點public static void insert(FindTree tree, int n) {if (tree.left == null && n < tree.val) {tree.left = new FindTree(n);return;}if (tree.right == null && n > tree.val) {tree.right = new FindTree(n);return;}if (n < tree.val) {insert(tree.left, n);} else {insert(tree.right, n);}}//查找節點public static boolean findNode(FindTree tree,int n){if(tree.val==n)return true;while(tree!=null){if(tree.val<n)tree = tree.right;else if(tree.val>n)tree = tree.left;elsereturn true;}return false;}//中序遍歷public static void showTree(FindTree tree) {if (tree == null)return;showTree(tree.left);System.out.print(tree.val + " ");showTree(tree.right);}// 層次遍歷public static void showTree1(FindTree tree){if (tree == null)return;Queue<FindTree> queue = new ArrayDeque<>();FindTree now = null;queue.offer(tree);while (!queue.isEmpty()) {now = queue.poll();System.out.print(now.val + " ");if (now.left != null)queue.offer(now.left);if (now.right != null)queue.offer(now.right);}}//刪除節點public static void deleteNode(FindTree tree ,int n){if(!findNode(tree, n)){System.out.println("刪除的元素不存在");return;}FindTree now = null;while(true){if(tree.left!=null) {if (tree.left.val == n) {tree.left = nextNode(tree.left);break;}}if(tree.right!=null) {if (tree.right.val == n) {tree.right = nextNode(tree.right);break;}}if(tree.val<n)tree = tree.left;elsetree = tree.right;}}//找到刪除之后的備胎private static FindTree nextNode(FindTree tree){if(tree.left==null&&tree.right==null)return null; //第一種情況 刪除的節點左右孩子都是空else if(tree.left==null)return tree.right; // 第二種情況左孩子空else if(tree.right==null) return tree.left; //第三種情況右孩子空else { //第四種情況FindTree now = tree.right;if(now.left==null){now.left = tree.left;return now;}else{while(now.left.left!=null)now = now.left;FindTree temp = now.left;now.left = null;temp.left = tree.left;temp.right = tree.right;return temp;}}} }
查找和增加的算法都很常規,刪除稍微復雜點:
刪除的思路是:找到刪除的那個節點,保存它的父節點。讓父節點指向新的刪除完的子樹
刪除的節點情況分為:
刪除的節點左右孩子都是空的,直接讓父節點指向null
刪除的節點左孩子為空,右不空,讓父節點指向右子樹
刪除的節點左孩子不為空,右空,讓父節點指向左子樹
刪除的節點左右都不為空,這時候應當找到右子樹的最小節點,來“繼承“被刪除的節點
? ? 所以 又有如下兩種情況 :一是子樹沒有左邊分支,也就是下圖中40就是最小的? 二是有左邊的分叉,這時38就是最小的
?
?
?
另外 由于整個類的定義問題,刪除根節點的操作沒法實現,因為我這里把根節點作為參數了,java又是值傳遞,所以我另寫了一個方法實現
起始 就是調用找備胎節點的方法就行了
public static FindTree deleteRoot(FindTree tree){return nextNode(tree); }測試如下:
public class TreeTest {public static void main(String[] args) {FindTree findTree = new FindTree(18);FindTree.insert(findTree, 32);FindTree.insert(findTree, 26);FindTree.insert(findTree, 25);FindTree.insert(findTree, 30);FindTree.insert(findTree, 40);FindTree.insert(findTree, 44);FindTree.showTree(findTree);System.out.println();FindTree.showTree1(findTree);FindTree.deleteNode(findTree, 32);System.out.println();FindTree.showTree(findTree);System.out.println();FindTree.showTree1(findTree);} }
?
?
?
二? 、二叉堆(大根堆、小根堆)
二叉堆邏輯上是一顆樹,滿足根節點是最值,根節點是整顆樹最小(大)的,左節點是整顆左子樹最(小)的。二叉堆邏輯上是一顆完全二叉樹,一般用數組就可以實現。二叉樹的一個應用堆排序,主要最核心的兩個操作是:首先增加一個元素,一般到添加到尾部,此時要對數組進行上浮操作;其次是刪除一個元素,這里只實現刪除最值元素,
也就是最值元素,此時把最后一個元素調到第一次,執行下墜操作。這部分漫畫算法里講的很好,下面是代碼實現的一個二叉堆的結構: public class MyHeap {private int arr[];int size;MyHeap() {this(20);} //不指定堆的大小,就自定義為20MyHeap(int n) {arr = new int[n];}public boolean isEmpty(){return size == 0;} //當前堆是不是空的public void push(int n) {if(size==arr.length){throw new RuntimeException("堆滿了");}arr[size] = n;int child = size;int par = (child - 1) / 2;int temp = arr[child];while (child > 0 && temp < arr[par]) {arr[child] = arr[par];child = par;par = (child - 1) / 2;}arr[child] = temp;size++;}//彈出arr[0]的元素 并把尾部的元素調到arr[0] 執行下墜操作public int pop(){int now = arr[0];int temp = arr[size-1];int left = 1;int par = 0;while(left<size-1){if(left==size-2){if(temp<arr[left])break;}else{if(temp<arr[left]&&temp<arr[left+1])break;}if(left!=size-2&&arr[left]>arr[left+1]){left++;}arr[par] = arr[left];par = left;left = 2 * par + 1;}arr[par] = temp;size--;return now;}}
public class TreeTest {public static void main(String[] args) { // FindTree findTree = new FindTree(18); // FindTree.insert(findTree, 32); // FindTree.insert(findTree, 26); // FindTree.insert(findTree, 25); // FindTree.insert(findTree, 30); // FindTree.insert(findTree, 40); // FindTree.insert(findTree, 44); // // FindTree.showTree(findTree); // System.out.println(); // FindTree.showTree1(findTree); // FindTree.deleteNode(findTree, 32); // System.out.println(); // FindTree.showTree(findTree); // System.out.println(); // FindTree.showTree1(findTree);MyHeap heap = new MyHeap(20);heap.push(2);heap.push(10);heap.push(1);heap.push(20);heap.push(-5);heap.push(-5);while(!heap.isEmpty()){System.out.println(heap.downAdjust());}} }
測試結果如下:
?
轉載于:https://www.cnblogs.com/caijiwdq/p/11032220.html
總結
以上是生活随笔為你收集整理的算法与数据结构 (三) 二叉树的简单应用 二叉查找树,二叉堆排序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: docker镜像和容器区别
- 下一篇: JVM分析