二进制搜索树

by Kevin Turney

凯文·特尼(Kevin Turney)

数据结构101:二叉搜索树 (Data Structures 101: Binary Search Trees)

如何结合插入链表的效率和快速搜索有序数组。 (How to combine the efficiency of insertion of a Linked List and the quick search of an ordered array.)

什么是二叉搜索树? (What is a Binary Search Tree?)

Let’s start with basic terminology so we may share the same language and investigate related concepts. First, what are the principles that define a Binary Search Tree?

让我们从基本术语开始,以便我们可以共享相同的语言并研究相关的概念。 首先,定义二进制搜索树的原理是什么?

* From here on out I will use “BST” for brevity

*为了简便起见,我将使用“ BST”

A BST is considered a data structure made up of nodes, like Linked Lists. These nodes are either null or have references (links) to other nodes. These ‘other’ nodes are child nodes, called a left node and right node. Nodes have values. These values determine where they are placed within the BST.

BST被认为是由节点 (如链表)组成的数据结构 这些节点为null或具有对其他节点的引用(链接)。 这些“其他”节点是子节点,称为左节点和右节点。 节点具有 。 这些值确定它们在BST中的放置位置。

Similarly to a linked list, each node is referenced by only one other node, its parent (except for the root node). So we can say that each node in a BST is in itself a BST. Because further down the tree, we reach another node and that node has a left and a right. Then depending on which way we go, that node has a left and a right and so on.

与链表类似,每个节点由其父节点(根节点除外)另一个节点引用。 因此,我们可以说BST中的每个节点本身就是BST。 因为在树的更下方,我们到达了另一个节点,并且该节点具有左侧和右侧。 然后根据我们走的路,那个节点有一个左和一个右,依此类推。

1. The left node is always smaller than its parent.

1.左节点始终小于其父节点。

2. The right node is always greater than its parent.

2.右节点始终大于其父节点。

3. A BST is considered balanced if every level of the tree is fully filled with the exception of the last level. On the last level, the tree is filled left to right.

3.如果树的每个级别都已完全填充(最后一个级别除外),则认为BST处于平衡状态。 在最后一级,树从左到右填充。

4. A Perfect BST is one in which it is both full and complete (all child nodes are on the same level and each node has a left and a right child node).

4.完美的BST是完全和完整的BST(所有子节点处于同一级别,并且每个节点都有左和右子节点)。

我们为什么要使用这个? (Why would we use this?)

What are some real-world examples of BST’s? Trees are often used in search, game logic, autocomplete tasks, and graphics.

BST的一些实际示例是什么? 树通常用于搜索,游戏逻辑,自动完成任务和图形中。

Speed. As mentioned earlier, the BST is an ordered data structure. Upon insertion, the nodes are placed in an orderly fashion. This inherent order makes searching fast. Similar to binary search (with an array that is sorted), we cut the amount of data to sort through by half on each pass. For example, suppose we are looking for a small node value. On each pass, we keep moving along the leftmost node. This eliminates half the greater values automatically!

速度。 如前所述,BST是有序的数据结构。 插入后,将节点有序放置。 这种固有的顺序使搜索变得更快。 类似于二进制搜索(对数组进行排序),我们将每次遍历将要排序的数据量减少一半。 例如,假设我们正在寻找一个小的节点值。 每次通过时,我们都会沿着最左边的节点移动。 这将自动消除较大值的一半!

Also, unlike an array, the data is stored by reference. As we add to the data structure, we create a new chunk in memory and link to it. This is faster than creating a new array with more space and then inserting the data from the smaller array to the new, larger one.

而且,与数组不同,数据是通过引用存储的。 当我们添加到数据结构时,我们在内存中创建了一个新块并链接到它。 这比创建具有更多空间的新阵列然后将数据从较小的阵列插入到较大的新阵列中要快。

In short, inserting, deleting and searching are the all-stars for a BST

简而言之,插入,删除和搜索是BST的全明星

Now that we understand the principles, the benefits, and the basic components of a BST, let’s implement one in javascript.

现在,我们了解了BST的原理,好处和基本组件,下面我们来用javascript实现它。

The API for a BST consists of the following: Insert, Contains, Get Min, Get Max, Remove Node, Check if Full, Is Balanced, and the types of Search — Depth First (preOrder, inOrder, postOrder), Breadth First Search, and lastly Get Height. That’s a big API, just take it one section at a time.

BST的API包括以下内容: 插入,包含,获取最小值,获取最大值,删除节点,检查是否已满,是否平衡以及搜索的类型- 深度优先(preOrder,inOrder,postOrder),宽度优先搜索 ,最后得到身高 。 那是一个很大的API,一次只需要一节。

实作 (Implementation)

The constructor

构造函数

The BST is made up of nodes, and each node has a value.

BST由节点组成,每个节点都有一个值。

function Node(value){  this.value = value;  this.left = null;  this.right = null;}

The BST constructor is made up of a root node.

BST构造函数由根节点组成。

function BinarySearchTree() { this.root = null;}
let bst = new BST();let node = new Node();
console.log(node, bst); // Node { value: undefined, left: null, right: null } BST { root: null }

… so far so good.

… 到目前为止,一切都很好。

插入 (Insertion)

BinarySearchTree.prototype.insert = function(value){ let node = new Node(value); if(!this.root) this.root = node; else{    let current = this.root;    while(!!current){       if(node.value < current.value){       if(!current.left){           current.left = node;           break;         }         current = current.left;         }        else if(node.value > current.value){         if(!current.right){            current.right = node;            break;           }          current = current.right;          }         else {          break;           }         }        }    return this; };
let bst = new BST();bst.insert(25); // BST { root: Node { value: 25, left: null, right: null } }

Let’s add some more values.

让我们添加更多的值。

bst.insert(40).insert(20).insert(9).insert(32).insert(15).insert(8).insert(27);
BST { root:  Node { value: 25, left: Node { value: 20, left: [Object], right: null }, right: Node { value: 40, left: [Object], right: null } } }

For a cool visualization Go Here!!

对于一个很酷的视觉去这里 !

Let’s unpack this.

让我们打开包装。

  1. First, we pass a value and create a new node首先,我们传递一个值并创建一个新节点
  2. Check if there is a root, if not, set this newly created node to the root node检查是否存在根,如果没有,则将此新创建的节点设置为根节点
  3. If there is a root node, we create a variable declared “current”, and set its value to the root node如果存在根节点,我们创建一个声明为“ current”的变量,并将其值设置为根节点
  4. If the newly created node.value is smaller than the root node, we will move left如果新创建的node.value小于根节点,我们将向左移动
  5. We keep comparing this node.value to left nodes.我们一直在比较这个node.value和左边的节点。
  6. If the value is small enough and we reach a point where there are no more left nodes, we place this item here.如果该值足够小,并且我们到达一个不再有剩余节点的点,则将此项放置在此处。
  7. If the node.value is greater we repeat the same steps as above except we move along the right.如果node.value更大,我们将重复上述步骤,只是沿着右边移动。
  8. We need the break statements because there is no count step to terminate the while loop.我们需要break语句,因为没有计数步骤可以终止while循环。

包含 (Contains)

This is a pretty straightforward approach.

这是一个非常简单的方法。

BinarySearchTree.prototype.contains = function(value){ let current = this.root; while(current){ if(value === current.value) return true; if(value < current.value) current = current.left; if(value > current.value) current = current.right; } return false;};

获得最小和获得最大。 (Get Min and Get Max.)

Keep traversing left to the smallest value or right for the largest.

继续向左移动到最小值或向右移动到最大值。

BinarySearchTree.prototype.getMin = function(node){ if(!node) node = this.root; while(node.left) { node = node.left; } return node.value};
BinarySearchTree.prototype.getMax = function(node){ if(!node) node = this.root; while(node.right) { node = node.right; } return node.value;};

清除 (Removal)

Removing a node is the trickiest operation, because nodes have to be reordered to maintain the properties of a BST. There is a case if a node has only one child and a case if there is both a left and a right node. We use the larger helper function to do the heavy lifting.

删除节点是最棘手的操作,因为必须重新排序节点才能维护BST的属性。 有一个节点只有一个孩子的情况,有一个左右节点都存在的情况。 我们使用较大的辅助函数来完成繁重的工作。

BinarySearchTree.prototype.removeNode = function(node, value){ if(!node){   return null; } if(value === node.value){ // no children if(!node.left && !node.right) return null; // one child and it’s the right if(!node.left) node.right;// one child and it’s the left if(!node.right) node.left;  // two kids const temp = this.getMin(node.right); node.value = temp; node.right = this.removeNode(node.right, temp); return node; } else if(value < node.value) {     node.left = this.removeNode(node.left, value);     return node; } else  {     node.right = this.removeNode(node.right, value);     return node;   }};
BinarySearchTree.prototype.remove = function(value){ this.root = this.removeNode(this.root, value);};

It works like this…

它是这样的……

Unlike deleteMin and deleteMax, where we can just traverse all the way left or all the way right and pick off the last value, we have to take out a node and then replace it with something. This solution was developed in 1962 by T. Hibbard. We account for the case where we can delete a node with only one child or none, that’s minor. If no children, no problem. If a child is present, that child just moves up one.

与deleteMin和deleteMax不同,在其中我们可以一直遍历或完全遍历并选择最后一个值,我们必须取出一个节点,然后用某种东西替换它。 该解决方案由T. Hibbard于1962年开发。 我们考虑了以下情况:可以删除只有一个孩子或没有一个孩子的节点,这是次要的。 如果没有孩子,没问题。 如果有一个孩子在场,那么那个孩子只会向上移动一个。

But with a node scheduled to be removed that has two children, which child takes its place? Certainly, we can’t move a larger node down. So what we do is replace it with its successor, the next kingpin. We have to find the smallest right child on the right that is larger than the left child.

但是,如果要删除一个有两个子节点的节点,那么哪个子节点代替了它? 当然,我们不能将更大的节点向下移动。 因此,我们要做的是将其替换为下一个主销。 我们必须在右侧找到比左侧孩子大的最小右侧孩子。

  1. Create a temp value and store the smallest node on its right. What this does is satisfy the property that values to the left are still smaller and values to the right are still greater.创建一个临时值,并在其右侧存储最小的节点。 这样做是满足以下属性:左侧的值仍然较小,右侧的值仍然较大。
  2. Reset the node’s value to this temp variable将节点的值重置为此临时变量
  3. Remove the right node.删除正确的节点。
  4. Then we compare values on the left and the right and determine the assigned value.然后,我们比较左侧和右侧的值并确定分配的值。

This is best explained with a picture:

最好用图片来解释:

正在搜寻 (Searching)

There are two types of search, Depth First and Breadth First. Breadth First is simply stopping at each level on the way down. It looks like this: we start at the root, then the left child, then the right child. Move to the next level, left child then right child. Think of this as moving horizontally. We employ, I should say simulate, a queue to help order the process. We pass a function, because many times we want to operate on a value.

有两种搜索类型,深度优先和宽度优先。 广度优先只是在下降的过程中停在每个级别。 看起来像这样:我们从根开始,然后是左孩子,然后是右孩子。 移至下一个级别,先是左孩子,然后是右孩子。 认为这是水平移​​动。 我应该说,模拟,我们使用一个队列来帮助订购流程。 我们传递一个函数,因为很多时候我们想对一个值进行运算。

BinarySearchTree.prototype.traverseBreadthFirst = function(fn) { let queue = []; queue.push(this.root); while(!!queue.length) {   let node = queue.shift();   fn(node);   node.left && queue.push(node.left);   node.right && queue.push(node.right);  }}

Depth First Search involves moving down the BST in a specified manner, either, preOrder, inOrder, or postOrder. I’ll explain the differences shortly.

深度优先搜索涉及以指定的方式向下移动BST,即preOrder,inOrder或postOrder。 我将尽快解释差异。

In the spirit of concise code, we have a basic traverseDepthFirst function and we pass a function and a method. Again the function implies that we want to do something to the values along the way, while the method is the type of search we wish to perform. In the traverseDFS, we have a fallback: preOrder search in place.

本着简洁代码的精神,我们有一个基本的traverseDepthFirst函数,并传递了一个函数和一个方法。 同样,该函数暗示我们要沿途对值做一些事情,而该方法是我们希望执行的搜索类型。 在traverseDFS中,我们有一个后备:preOrder搜索到位。

Now, how is each one different? First, let’s dispatch inOrder. It should be self-explanatory but it isn’t. Do we mean in order of insertion, in order of highest to lowest or lowest to highest? I just wanted you to consider these things beforehand. In this case, yes, it does mean lowest to highest.

现在,每个有什么不同? 首先,让我们分派inOrder。 它应该是不言自明的,但事实并非如此。 我们是按插入顺序,按从最高到最低还是从最低到最高的顺序表示? 我只是希望您事先考虑这些事情。 在这种情况下,是的,它的意思是从最低到最高。

preOrder can be thought of as Parent, Left Child, then Right child.

preOrder可以被认为是Parent,Left Child,然后是Right child

postOrder as Left Child, Right Child, Parent.

postOrder作为左孩子,右孩子,父母

BinarySearchTree.prototype.traverseDFS = function(fn, method){ let current = this.root; if(!!method) this[method](current, fn); else this._preOrder(current, fn);};
BinarySearchTree.prototype._inOrder = function(node, fn){ if(!!node){ this._inOrder(node.left, fn); if(!!fn) fn(node); this._inOrder(node.right, fn); }};
BinarySearchTree.prototype._preOrder = function(node, fn){ if(node){ if(fn) fn(node); this._preOrder(node.left, fn); this._preOrder(node.right, fn); }};
BinarySearchTree.prototype._postOrder = function(node, fn){ if(!!node){ this._postOrder(node.left, fn); this._postOrder(node.right, fn); if(!!fn) fn(node); }};

检查BST是否已满 (Check if the BST is full)

Remember from earlier, a BST is full if every node has Zero or Two children.

请记住,如果每个节点都有零个或两个孩子,则BST已满。

// a BST is full if every node has zero two children (no nodes have one child)
BinarySearchTree.prototype.checkIfFull = function(fn){ let result = true; this.traverseBFS = (node) => {   if(!node.left && !node.right) result = false;   else if(node.left && !node.right) result = false;  } return result;};

获取BST的高度 (Get Height of BST)

What does it mean to get the height of a tree? Why is this important? This is where Time Complexity (aka Big O) comes into play. Basic operations are proportional to the height of a tree. So as we alluded to earlier, if we search for a particular value, the number of operations we have to do is halved on each step.

得到一棵树的高度是什么意思? 为什么这很重要? 这就是时间复杂性 (又名Big O)发挥作用的地方。 基本操作与树的高度成正比。 因此,正如我们前面提到的,如果我们搜索一个特定的值,那么每一步要做的操作数量将减半。

That means if we have a loaf of bread and cut it in half, then cut that half in half, and keep doing that till we get the exact piece of bread we want.

这意味着,如果我们有一条面包,将其切成两半,然后再切成两半,然后继续这样做,直到得到我们想要的确切面包。

In computer science, this is called O(log n). We start with an input size of some sort, and over time that size gets smaller (kind of flattening out). A straight linear search is denoted as O(n), as the input size increases so does the time it takes to run operations. O(n) conceptually is a 45-degree line starting at origin zero on a chart and moving right. The horizontal scale represents the size of an input and the vertical scale represents the time it takes to complete.

在计算机科学中,这称为O(log n)。 我们从某种输入大小开始,随着时间的流逝,大小变得越来越小(有点扁平化)。 直线线性搜索表示为O(n),随着输入大小的增加,运行操作所需的时间也会增加。 O(n)在概念上是一条45度线,从图表的原点零开始向右移动。 水平刻度表示输入的大小,垂直刻度表示完成操作所需的时间。

Constant time is O(1). No matter how large or small the input size is, the operation takes place in the same amount of time. For example, push() and pop() off of an array are constant time. Looking up a value in a HashTable is constant time.

恒定时间为O(1)。 无论输入大小是大还是小,操作都将在相同的时间内进行。 例如,数组的push()和pop()是恒定时间。 在HashTable中查找值是固定时间。

I will explain more about this in a future article, but I wanted to arm you with this knowledge for now.

我将在以后的文章中对此进行详细说明,但现在我想用这些知识来武装您。

Back to height.

回到身高。

We have a recursive function, and our base case is: ‘if we have no node then we start at this.root’. This implies that we can start at values lower in the tree and get tree sub-heights.

我们有一个递归函数,我们的基本情况是: “如果没有节点,那么我们从this.root开始” 这意味着我们可以从树中较低的值开始获取树的子高度。

So if we pass in this.root to start, we recursively move down the tree and add the function calls to the execution stack (other articles here). When we get to the bottom, the stack is filled. Then the calls get executed and we compare the heights of the left and the heights of the right and increment by one.

因此,如果我们传递this.root来开始,我们将递归地向下移动树,并将函数调用添加到执行堆栈中(此处还有其他文章)。 当我们到达底部时,堆栈已填充。 然后调用被执行,我们比较左边的高度和右边的高度,然后加一。

BinarySearchTree.prototype._getHeights = function(node){ if(!node) return -1; let left = this._getHeights(node.left); let right = this._getHeights(node.right); return Math.max(left, right) + 1;};
BinarySearchTree.prototype.getHeight = function(node){ if(!node) node = this.root; return this._getHeights(node);};

最后,是平衡的 (Lastly, Is Balanced)

What we are doing is checking if the tree is filled at every level, and on the last level, if it is filled left to right.

我们正在做的是检查树是否在每个级别都已填充,并且在最后一级是否从左到右填充。

BinarySearchTree.prototype._isBalanced = function(node){ if(!node) return true; let heightLeft = this._getHeights(node.left); let heightRight = this._getHeights(node.right); let diff = Math.abs(heightLeft — heightRight); if(diff > 1) return false; else return this._isBalanced(node.left) &&    this._isBalanced(node.right);};
BinarySearchTree.prototype.isBalanced = function(node){ if(!node) node = this.root; return this._isBalanced(node);};

打印 (Print)

Use this to visualize all the methods you see, especially depth first and breadth first traversals.

使用此工具可视化您看到的所有方法,尤其是深度优先遍历和宽度优先遍历。

BinarySearchTree.prototype.print = function() { if(!this.root) {   return console.log(‘No root node found’); } let newline = new Node(‘|’); let queue = [this.root, newline]; let string = ‘’; while(queue.length) {   let node = queue.shift();   string += node.value.toString() + ‘ ‘;   if(node === newline && queue.length) queue.push(newline);    if(node.left) queue.push(node.left);   if(node.right) queue.push(node.right);  } console.log(string.slice(0, -2).trim());};

Our Friend Console.log!! Play around and experiment.

我们的朋友Console.log! 玩耍并尝试。

const binarySearchTree = new BinarySearchTree();binarySearchTree.insert(5);binarySearchTree.insert(3);
binarySearchTree.insert(7);binarySearchTree.insert(2);binarySearchTree.insert(4);binarySearchTree.insert(4);binarySearchTree.insert(6);binarySearchTree.insert(8);binarySearchTree.print(); // => 5 | 3 7 | 2 4 6 8
binarySearchTree.contains(4);
//binarySearchTree.printByLevel(); // => 5 \n 3 7 \n 2 4 6 8console.log('--- DFS inOrder');
binarySearchTree.traverseDFS(function(node) { console.log(node.value); }, '_inOrder'); // => 2 3 4 5 6 7 8
console.log('--- DFS preOrder');
binarySearchTree.traverseDFS(function(node) { console.log(node.value); }, '_preOrder'); // => 5 3 2 4 7 6 8
console.log('--- DFS postOrder');
binarySearchTree.traverseDFS(function(node) { console.log(node.value); }, '_postOrder'); // => 2 4 3 6 8 7 5
console.log('--- BFS');
binarySearchTree.traverseBFS(function(node) { console.log(node.value); }); // => 5 3 7 2 4 6 8
console.log('min is 2:', binarySearchTree.getMin()); // => 2
console.log('max is 8:', binarySearchTree.getMax()); // => 8
console.log('tree contains 3 is true:', binarySearchTree.contains(3)); // => true
console.log('tree contains 9 is false:', binarySearchTree.contains(9)); // => false
// console.log('tree height is 2:', binarySearchTree.getHeight()); // => 2
console.log('tree is balanced is true:', binarySearchTree.isBalanced(),'line 220'); // => true
binarySearchTree. remove(11); // remove non existing node
binarySearchTree.print(); // => 5 | 3 7 | 2 4 6 8
binarySearchTree.remove(5); // remove 5, 6 goes up
binarySearchTree.print(); // => 6 | 3 7 | 2 4 8
console.log(binarySearchTree.checkIfFull(), 'should be true');
var fullBSTree = new BinarySearchTree(10);
fullBSTree.insert(5).insert(20).insert(15).insert(21).insert(16).insert(13);
console.log(fullBSTree.checkIfFull(), 'should be true');
binarySearchTree.remove(7); // remove 7, 8 goes up
binarySearchTree.print(); // => 6 | 3 8 | 2 4
binarySearchTree.remove(8); // remove 8, the tree becomes unbalanced
binarySearchTree.print(); // => 6 | 3 | 2 4
console.log('tree is balanced is false:', binarySearchTree.isBalanced()); // => true
console.log(binarySearchTree.getHeight(),'height is 2')
binarySearchTree.remove(4);
binarySearchTree.remove(2);
binarySearchTree.remove(3);
binarySearchTree.remove(6);
binarySearchTree.print(); // => 'No root node found'
//binarySearchTree.printByLevel(); // => 'No root node found'
console.log('tree height is -1:', binarySearchTree.getHeight()); // => -1
console.log('tree is balanced is true:', binarySearchTree.isBalanced()); // => true
console.log('---');
binarySearchTree.insert(10);
console.log('tree height is 0:', binarySearchTree.getHeight()); // => 0
console.log('tree is balanced is true:', binarySearchTree.isBalanced()); // => true
binarySearchTree.insert(6);
binarySearchTree.insert(14);
binarySearchTree.insert(4);
binarySearchTree.insert(8);
binarySearchTree.insert(12);
binarySearchTree.insert(16);
binarySearchTree.insert(3);
binarySearchTree.insert(5);
binarySearchTree.insert(7);
binarySearchTree.insert(9);
binarySearchTree.insert(11);
binarySearchTree.insert(13);
binarySearchTree.insert(15);
binarySearchTree.insert(17);
binarySearchTree.print(); // => 10 | 6 14 | 4 8 12 16 | 3 5 7 9 11 13 15 17
binarySearchTree.remove(10); // remove 10, 11 goes up
binarySearchTree.print(); // => 11 | 6 14 | 4 8 12 16 | 3 5 7 9 x 13 15 17
binarySearchTree.remove(12); // remove 12; 13 goes up
binarySearchTree.print(); // => 11 | 6 14 | 4 8 13 16 | 3 5 7 9 x x 15 17
console.log('tree is balanced is true:', binarySearchTree.isBalanced()); // => true
//console.log('tree is balanced optimized is true:', binarySearchTree.isBalancedOptimized()); // => true
binarySearchTree.remove(13); // remove 13, 13 has no children so nothing changes
binarySearchTree.print(); // => 11 | 6 14 | 4 8 x 16 | 3 5 7 9 x x 15 17
console.log('tree is balanced is false:', binarySearchTree.isBalanced()); // => false
// yields ...5 | 3 7 | 2 4 6 8--- DFS inOrder2345678--- DFS preOrder5324768--- DFS postOrder2436875--- BFS5372468min is 2: 2max is 8: 8tree contains 3 is true: truetree contains 9 is false: falsetree is balanced is true: true line 2205 | 3 7 | 2 4 6 86 | 3 7 | 2 4 8true 'should be true'true 'should be true'6 | 3 8 | 2 46 | 3 | 2 4tree is balanced is false: false2 'height is 2'No root node foundtree height is -1: -1tree is balanced is true: true---tree height is 0: 0tree is balanced is true: true10 | 6 14 | 4 8 12 16 | 3 5 7 9 11 13 15 1711 | 6 14 | 4 8 12 16 | 3 5 7 9 13 15 1711 | 6 14 | 4 8 13 16 | 3 5 7 9 15 17tree is balanced is true: true11 | 6 14 | 4 8 16 | 3 5 7 9 15 17tree is balanced is false: false

时间复杂度 (Time Complexity)

1. Insertion O(log n)2. Removal O(log n)3. Search O(log n)

1.插入O(log n)2。 去除O(log n)3。 搜索O(log n)

Wow, that is indeed a lot of information. I hope the explanations were as clear and as introductory as possible. Again, writing helps me solidify concepts and as Richard Feynman said, “When one person teaches, two learn.”

哇,确实是很多信息。 我希望这些解释尽可能清晰和介绍。 同样,写作可以帮助我巩固概念,正如理查德·费曼(Richard Feynman)所说:“一个人教书,两个人学习。”

翻译自: https://www.freecodecamp.org/news/data-structures-101-binary-search-tree-398267b6bff0/

二进制搜索树

二进制搜索树_数据结构101:二进制搜索树相关推荐

  1. 数据结构二叉排序树建立_数据结构101什么是二叉搜索树

    数据结构二叉排序树建立 In everyday life, we need to find things or make decisions, and one way to make that pro ...

  2. 适合初学者的数据结构_数据结构101:数组-初学者的直观介绍

    适合初学者的数据结构 了解您每天使用的数据结构. (Get to know the data structures that you use every day. ) Welcome! Let's S ...

  3. java负数转换二进制表示_负数的二进制和十进制之间的转换

    负数的二进制和十进制之间的转换: 1. 十进制负数转换为二进制的方法为: 1.将十进制转换为二进制数. 2.对该二进制数求反. 3.再将该二进制数加1. 总之就是将十进制数转换为二进制数求补码即为结果 ...

  4. 适合初学者的数据结构_数据结构101:图-初学者的直观介绍

    适合初学者的数据结构 了解您每天使用的数据结构 (Get to know the data structures that you use every day) Welcome! Let's Star ...

  5. 数据结构教程网盘链接_数据结构101:链接列表

    数据结构教程网盘链接 by Kevin Turney 凯文·特尼(Kevin Turney) Like stacks and queues, Linked Lists are a form of a ...

  6. c ++ 打印二进制_C / C ++中的二进制搜索树

    c ++ 打印二进制 In this article, we'll take a look at implementing a Binary Search Tree in C/C++. 在本文中,我们 ...

  7. 数据结构-二叉树、搜索树、平衡二叉树详解及C语言实现

    目录 1. 树概念及结构 1.1.树的概念 1.2.树的定义 1.3.树的一些基本术语 1.4.树的表示 1.4.1.儿子兄弟表示法 1.4.2.双亲表示法 1.4.3.孩子表示法 2.二叉树及存储结 ...

  8. 数据结构---二叉搜索树

    数据结构-二叉搜索树 原理:参考趣学数据结构 代码: 队列代码: #pragma once #define N 100 #define elemType bstTree* #include<st ...

  9. 数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

    在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉 ...

最新文章

  1. SpringSecurity过滤器链汇总
  2. 示廓灯——也就是前后位置等开启方法 还有该死的刮水器是长这样的
  3. java中的取模_Java 中的取模和取余
  4. [蓝桥杯2015初赛]生命之树-求树的最大子树权值和
  5. 2017ACM/ICPC广西邀请赛
  6. AT3877-[ARC089C]GraphXY【构造】
  7. [模拟] hdu 4452 Running Rabbits
  8. hdu1251(统计难题)
  9. 【图像融合】拉普拉斯金字塔融合
  10. 如何检查PHP数组是关联数组还是顺序数组?
  11. Win10电脑系统文件损坏怎么修复
  12. MongoDB的Go语言驱动----mgo的使用指南
  13. inner join去除重复_SQL多表查询:join表联结
  14. centos7 搭建安装zabbix3.0邮件告警实例(二)
  15. 短信接口哪家好 凌凯短信接口
  16. error: Libtool library used but 'LIBTOOL' is undefined
  17. 适用于顺序磁盘访问的1分钟法则
  18. 家园守卫战新系统冲入海盗营地漏洞,无限赚钱
  19. Win10配置TensorFlow
  20. python读文件的方法

热门文章

  1. js继承实现 狗类继承动物类
  2. log4j的使用 ideal java 114812280
  3. css3 3D动画 200303
  4. MarkDown基础语法记录
  5. alert.log中的minact-scn: useg scan erroring out with error e:376警告
  6. SSM+easyUI(框架的搭建)
  7. mysqlbinlog日志一天产生太多脚本
  8. javascript小技巧(转)
  9. Serverless实战 —— ​​​​​​​Laravel + Serverless Framework 快速创建 CMS 内容管理系统
  10. 全面、详细的前端组件库