结构树 树表设计 二叉树

结构树 树表设计 二叉树
结构树 树表设计 二叉树

The Nested Model 树形结构

先把树按水平的方式摆开,如下图

然后按前序遍历的方法,为每一个结点编号,每一个结点都有左、右的编号,根结点从1开始开始计算。我们分别把左右编号称为左值和右值。

根据前序遍历的规律,我们可以知道,每一个结点的子结点的左值比父结点左值大而比父结点的右值小。例如 Fruit(2,11) 的子结点 Red(3,6)、Cherry(4,5)、Yellow(7,10)、Banana(8,9) ,可以看到Red、Cherry、Yellow、Banana的左值均比Fruit大,而右值均比Fruit小。

数据库设计如下:

Java代码

1.CREATE TABLE `nested_category` (

2. `id` int(11) NOT NULL AUTO_INCREMENT,

3. `name` varchar(16) DEFAULT NULL,

4. `parent` int(11) DEFAULT NULL,

5. `lft` int(11) DEFAULT NULL,

6. `rgt` int(11) DEFAULT NULL,

7. PRIMARY KEY (`id`)

8. )

常用到的SQL语句:

返回完整的树(Retrieving a Full Tree)

Java代码

1.SELECT https://www.360docs.net/doc/0818574078.html,

2.

3. FROM nested_category node, nested_category parent

4. WHERE node.lft BETWEEN parent.lft AND parent.rgt

5. AND https://www.360docs.net/doc/0818574078.html, = 'Food'

6. ORDER BY node.lft

返回某结点的祖谱路径(Retrieving a Single Path)

Java代码

1.SELECT https://www.360docs.net/doc/0818574078.html,

2. FROM nested_category node, nested_category parent

3. WHERE node.lft BETWEEN parent.lft AND parent.rgt

4. AND https://www.360docs.net/doc/0818574078.html, = 'Yellow'

5. ORDER BY node.lft

返回所有节点的深度(Finding the Depth of the Nodes)

提示:所有父结点的个数即为深度,最外面那层select 是为了对node.lft进行排序,而between and 操作是相当于>= and <=,所以会包括结点本身,所以要减一

Java代码

1.SELECT V.*

2. FROM (SELECT https://www.360docs.net/doc/0818574078.html,, (COUNT(https://www.360docs.net/doc/0818574078.html,) - 1) depth

3. FROM nested_category node, nested_category parent

4. WHERE node.lft BETWEEN parent.lft AND parent.rgt

5. GROUP BY https://www.360docs.net/doc/0818574078.html,) V,

6. nested_category T

7. WHERE https://www.360docs.net/doc/0818574078.html, = https://www.360docs.net/doc/0818574078.html,

8. ORDER BY T.Lft

返回子树的深度(Depth of a Sub-Tree)

提示:首先,第一步,找到父结点的深度,在前面的SQL中加一个限制条件"https://www.360docs.net/doc/0818574078.html,='Yellow'",得到了父结点的全局深度后,便与node、parent、subParent进行条件比较,找到指定父结点的所有子结点(包括父结点本身),然后用子结点的全局深度减去父结点的全局深度,就可以得到子结点相对于父结点的深度,而父结点本身的深度为0

parent 是为了找到子结点的全局深度,而subParent是为了得到父结点的

lft,rgt的结点信息,node就是子结点本身,最外面那层是为了对lft进行排序。

Java代码

1.SELECT V.*

2. FROM (SELECT https://www.360docs.net/doc/0818574078.html,,

3. (COUNT(https://www.360docs.net/doc/0818574078.html,) - (AVG(sub_tree.depth) + 1))

depth

4. FROM nested_category node,

5. nested_category parent,

6. nested_category sub_parent,

7. (SELECT V.*

8. FROM (SELECT https://www.360docs.net/doc/0818574078.html,, (COUNT(https://www.360docs.net/doc/0818574078.html,) -

1) depth

9. FROM nested_category node, nested_cate

gory parent

10. WHERE node.lft BETWEEN parent.lft AND p

arent.rgt

11. AND https://www.360docs.net/doc/0818574078.html, = 'Yellow'

12. GROUP BY https://www.360docs.net/doc/0818574078.html,) V,

13. nested_category T

14. WHERE https://www.360docs.net/doc/0818574078.html, = https://www.360docs.net/doc/0818574078.html,

15. ORDER BY T.lft) sub_tree

16. WHERE node.lft BETWEEN parent.lft AND parent.rgt

17. AND node.lft BETWEEN sub_parent.lft AND sub_parent.rg

t

18. AND sub_https://www.360docs.net/doc/0818574078.html, = sub_https://www.360docs.net/doc/0818574078.html,

19. GROUP BY https://www.360docs.net/doc/0818574078.html,) V,

20. nested_category T

21.WHERE https://www.360docs.net/doc/0818574078.html, = https://www.360docs.net/doc/0818574078.html,

22.ORDER BY T.Lft

返回某结点的直接子树(Find the Immediate Subordinates of a Node)

提示:某结点A的所有子结点的深度(depth)减去A结点的深度等于1的所有结点即为A的直接结点

Java代码

1.SELECT V.*

2. FROM (SELECT https://www.360docs.net/doc/0818574078.html,,

3. (COUNT(https://www.360docs.net/doc/0818574078.html,) - (AVG(sub_tree.depth) + 1)) depth

4. FROM nested_category node,

5. nested_category parent,

6. nested_category sub_parent,

7. (SELECT V.*

8. FROM (SELECT https://www.360docs.net/doc/0818574078.html,, (COUNT(https://www.360docs.net/doc/0818574078.html,) - 1) depth

9. FROM nested_category node, nested_category parent

10. WHERE node.lft BETWEEN parent.lft AND parent.rgt

11. AND https://www.360docs.net/doc/0818574078.html, = 'Yellow'

12. GROUP BY https://www.360docs.net/doc/0818574078.html,) V,

13. nested_category T

14. WHERE https://www.360docs.net/doc/0818574078.html, = https://www.360docs.net/doc/0818574078.html,

15. ORDER BY T.lft) sub_tree

16. WHERE node.lft BETWEEN parent.lft AND parent.rgt

17. AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt

18. AND sub_https://www.360docs.net/doc/0818574078.html, = sub_https://www.360docs.net/doc/0818574078.html,

19. GROUP BY https://www.360docs.net/doc/0818574078.html,) V,

20. nested_category T

21. WHERE https://www.360docs.net/doc/0818574078.html, = https://www.360docs.net/doc/0818574078.html,

22.and V.depth <= 1

23. and V.depth > 0

24. ORDER BY T.Lft

返回所有的叶子节点(Finding all the Leaf Nodes)

提示:左值与右值相减为1的所有结点即为叶子结点

Java代码

1.SELECT name FROM nested_category WHERE rgt = lft + 1

插入节点(Adding New Nodes)

即所有的后续的子结点都相应的加2

Java代码

1.LOCK TABLE nested_category WRITE;

2.SELECT @myRight := rgt FROM nested_category WHERE name = 'TELEV

ISIONS';

3.UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myRight;

4.UPDATE nested_category SET lft = lft + 2 WHERE lft > @myRight;

5.INSERT INTO nested_category

6.(name, lft, rgt)

7.VALUES

8.('GAME CONSOLES', @myRight + 1, @myRight + 2);

9.UNLOCK TABLES;

删除节点(Deleting Nodes)

提示:所有后续的结点都相应的减去结点删除后的左右值的偏差

Java代码

1.LOCK TABLE nested_category WRITE;

2.SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft +

1

3. FROM nested_category

4. WHERE name = 'GAME CONSOLES';

5.DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRi

ght;

6.UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @my

Right;

7.UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @my

Right;

8.UNLOCK TABLES;

Introduction

Most users at one time or another have dealt with hierarchical data in a SQL database and no doubt learned that the management of hierarchical data is not what a relational database is intended for. The tables of a relational database are not hierarchical (like XML), but are simply a flat list. Hierarchical data has a parent-child relationship that is not naturally represented in a relational database table.

For our purposes, hierarchical data is a collection of data where each item has a single parent and zero or more children (with the exception of the root item, which has no parent). Hierarchical data can be found in a variety of database applications, including forum and mailing list threads, business organization charts, content management categories, and product categories. For our purposes we will use the following product category hierarchy from an fictional electronics store:

These categories form a hierarchy in much the same way as the other examples cited above. In this article we will examine two models for dealing with hierarchical data in MySQL, starting with the traditional adjacency list model.

The Adjacency List Model

Typically the example categories shown above will be stored in a table like the following (I'm including full CREATE and INSERT statements so you can follow along):

CREATE TABLE category(

category_id INT AUTO_INCREMENT PRIMARY KEY,

name VARCHAR(20) NOT NULL,

parent INT DEFAULT NULL);

INSERT INTO category

VALUES(1,'ELECTRONICS',NULL),(2,'TELEVISIONS',1),(3,'TUBE',2),

(4,'LCD',2),(5,'PLASMA',2),(6,'PORTABLE ELECTRONICS',1),

(7,'MP3 PLAYERS',6),(8,'FLASH',7),

(9,'CD PLAYERS',6),(10,'2 WAY RADIOS',6);

SELECT * FROM category ORDER BY category_id;

+-------------+----------------------+--------+

| category_id | name | parent |

+-------------+----------------------+--------+

| 1 | ELECTRONICS | NULL |

| 2 | TELEVISIONS | 1 |

| 3 | TUBE | 2 |

| 4 | LCD | 2 |

| 5 | PLASMA | 2 |

| 6 | PORTABLE ELECTRONICS | 1 |

| 7 | MP3 PLAYERS | 6 |

| 8 | FLASH | 7 |

| 9 | CD PLAYERS | 6 |

| 10 | 2 WAY RADIOS | 6 |

+-------------+----------------------+--------+

10 rows in set (0.00 sec)

In the adjacency list model, each item in the table contains a pointer to its parent. The topmost element, in this case electronics, has a NULL value for its parent. The adjacency list model has the advantage of being quite simple, it is easy to see that FLASH is a child of mp3 players, which is a child of portable electronics, which is a child of electronics. While the adjacency list model can be dealt with fairly easily in client-side code, working with the model can be more problematic in pure SQL.

Retrieving a Full Tree

The first common task when dealing with hierarchical data is the display of the entire tree, usually with some form of indentation. The most common way of doing this is in pure SQL is through the use of a self-join:

SELECT https://www.360docs.net/doc/0818574078.html, AS lev1, https://www.360docs.net/doc/0818574078.html, as lev2, https://www.360docs.net/doc/0818574078.html, as lev3, https://www.360docs.net/doc/0818574078.html, as lev4 FROM category AS t1

LEFT JOIN category AS t2 ON t2.parent = t1.category_id

LEFT JOIN category AS t3 ON t3.parent = t2.category_id

LEFT JOIN category AS t4 ON t4.parent = t3.category_id

WHERE https://www.360docs.net/doc/0818574078.html, = 'ELECTRONICS';

+-------------+----------------------+--------------+-------+

| lev1 | lev2 | lev3 | lev4 |

+-------------+----------------------+--------------+-------+

| ELECTRONICS | TELEVISIONS | TUBE | NULL |

| ELECTRONICS | TELEVISIONS | LCD | NULL |

| ELECTRONICS | TELEVISIONS | PLASMA | NULL |

| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH |

| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS | NULL |

| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL |

+-------------+----------------------+--------------+-------+

6 rows in set (0.00 sec)

Finding all the Leaf Nodes

We can find all the leaf nodes in our tree (those with no children) by using a LEFT JOIN query:

SELECT https://www.360docs.net/doc/0818574078.html, FROM

category AS t1 LEFT JOIN category as t2

ON t1.category_id = t2.parent

WHERE t2.category_id IS NULL;

+--------------+

| name |

+--------------+

| TUBE |

| LCD |

| PLASMA |

| FLASH |

| CD PLAYERS |

| 2 WAY RADIOS |

+--------------+

Retrieving a Single Path

The self-join also allows us to see the full path through our hierarchies:

SELECT https://www.360docs.net/doc/0818574078.html, AS lev1, https://www.360docs.net/doc/0818574078.html, as lev2, https://www.360docs.net/doc/0818574078.html, as lev3, https://www.360docs.net/doc/0818574078.html, as lev4 FROM category AS t1

LEFT JOIN category AS t2 ON t2.parent = t1.category_id

LEFT JOIN category AS t3 ON t3.parent = t2.category_id

LEFT JOIN category AS t4 ON t4.parent = t3.category_id

WHERE https://www.360docs.net/doc/0818574078.html, = 'ELECTRONICS' AND https://www.360docs.net/doc/0818574078.html, = 'FLASH';

+-------------+----------------------+-------------+-------+

| lev1 | lev2 | lev3 | lev4 |

+-------------+----------------------+-------------+-------+

| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH |

+-------------+----------------------+-------------+-------+

1 row in set (0.01 sec)

The main limitation of such an approach is that you need one self-join for every level in the hierarchy, and performance will naturally degrade with each level added as the joining grows in complexity.

Limitations of the Adjacency List Model

Working with the adjacency list model in pure SQL can be difficult at best. Before being able to see the full path of a category we have to know the level at which it resides. In addition, special care must be taken when deleting nodes because of the potential for orphaning an entire sub-tree in the process (delete the portable electronics category and all of its children are orphaned). Some of these limitations can be addressed through the use of client-side code or stored procedures. With a procedural language we can start at the bottom of the tree and iterate upwards to return the full tree or a single path. We can also use procedural programming to delete nodes without orphaning entire sub-trees by promoting one child element and re-ordering the remaining children to point to the new parent.

The Nested Set Model

What I would like to focus on in this article is a different approach, commonly referred to as the Nested Set Model. In the Nested Set Model,

we can look at our hierarchy in a new way, not as nodes and lines, but as nested containers. Try picturing our electronics categories this way:

Notice how our hierarchy is still maintained, as parent categories envelop their children.We represent this form of hierarchy in a table through the use of left and right values to represent the nesting of our nodes:

CREATE TABLE nested_category (

category_id INT AUTO_INCREMENT PRIMARY KEY,

name VARCHAR(20) NOT NULL,

lft INT NOT NULL,

rgt INT NOT NULL

);

INSERT INTO nested_category

VALUES(1,'ELECTRONICS',1,20),(2,'TELEVISIONS',2,9),(3,'TUBE',3,4), (4,'LCD',5,6),(5,'PLASMA',7,8),(6,'PORTABLE ELECTRONICS',10,19), (7,'MP3 PLAYERS',11,14),(8,'FLASH',12,13),

(9,'CD PLAYERS',15,16),(10,'2 WAY RADIOS',17,18);

SELECT * FROM nested_category ORDER BY category_id;

+-------------+----------------------+-----+-----+

| category_id | name | lft | rgt |

+-------------+----------------------+-----+-----+

| 1 | ELECTRONICS | 1 | 20 |

| 2 | TELEVISIONS | 2 | 9 |

| 3 | TUBE | 3 | 4 |

| 4 | LCD | 5 | 6 |

| 5 | PLASMA | 7 | 8 |

| 6 | PORTABLE ELECTRONICS | 10 | 19 |

| 7 | MP3 PLAYERS | 11 | 14 |

| 8 | FLASH | 12 | 13 |

| 9 | CD PLAYERS | 15 | 16 |

| 10 | 2 WAY RADIOS | 17 | 18 |

+-------------+----------------------+-----+-----+

We use lft and rgt because left and right are reserved words in MySQL, see https://www.360docs.net/doc/0818574078.html,/doc/mysql/en/reserved-words.html for the full list of reserved words.

So how do we determine left and right values? We start numbering at the leftmost side of the outer node and continue to the right:

This design can be applied to a typical tree as well:

When working with a tree, we work from left to right, one layer at a time, descending to each node's children before assigning a right-hand number and moving on to the right. This approach is called the modified preorder tree traversal algorithm.

Retrieving a Full Tree

We can retrieve the full tree through the use of a self-join that links parents with nodes on the basis that a node's lft value will always appear between its parent's lft and rgt values:

SELECT https://www.360docs.net/doc/0818574078.html,

FROM nested_category AS node,

nested_category AS parent

WHERE node.lft BETWEEN parent.lft AND parent.rgt

AND https://www.360docs.net/doc/0818574078.html, = 'ELECTRONICS'

ORDER BY node.lft;

+----------------------+

| name |

+----------------------+

| ELECTRONICS |

| TELEVISIONS |

| TUBE |

| LCD |

| PLASMA |

| PORTABLE ELECTRONICS |

| MP3 PLAYERS |

| FLASH |

| CD PLAYERS |

| 2 WAY RADIOS |

+----------------------+

Unlike our previous examples with the adjacency list model, this query will work regardless of the depth of the tree. We do not concern ourselves with the rgt value of the node in our BETWEEN clause because the rgt value will always fall within the same parent as the lft values.

Finding all the Leaf Nodes

Finding all leaf nodes in the nested set model even simpler than the LEFT JOIN method used in the adjacency list model. If you look at the nested_category table, you may notice that the lft and rgt values for leaf nodes are consecutive numbers. To find the leaf nodes, we look for nodes where rgt = lft + 1:

SELECT name

FROM nested_category

WHERE rgt = lft + 1;

+--------------+

| name |

+--------------+

| TUBE |

| LCD |

| PLASMA |

| FLASH |

| CD PLAYERS |

| 2 WAY RADIOS |

+--------------+

Retrieving a Single Path

With the nested set model, we can retrieve a single path without having multiple self-joins:

SELECT https://www.360docs.net/doc/0818574078.html,

FROM nested_category AS node,

nested_category AS parent

WHERE node.lft BETWEEN parent.lft AND parent.rgt

AND https://www.360docs.net/doc/0818574078.html, = 'FLASH'

ORDER BY parent.lft;

+----------------------+

| name |

+----------------------+

| ELECTRONICS |

| PORTABLE ELECTRONICS |

| MP3 PLAYERS |

| FLASH |

+----------------------+

Finding the Depth of the Nodes

We have already looked at how to show the entire tree, but what if we want to also show the depth of each node in the tree, to better identify how each node fits in the hierarchy? This can be done by adding a COUNT function and a GROUP BY clause to our existing query for showing the entire tree:

SELECT https://www.360docs.net/doc/0818574078.html,, (COUNT(https://www.360docs.net/doc/0818574078.html,) - 1) AS depth

FROM nested_category AS node,

nested_category AS parent

WHERE node.lft BETWEEN parent.lft AND parent.rgt

GROUP BY https://www.360docs.net/doc/0818574078.html,

ORDER BY node.lft;

+----------------------+-------+

| name | depth |

+----------------------+-------+

| ELECTRONICS | 0 |

| TELEVISIONS | 1 |

| TUBE | 2 |

| LCD | 2 |

| PLASMA | 2 |

| PORTABLE ELECTRONICS | 1 |

| MP3 PLAYERS | 2 |

| FLASH | 3 |

| CD PLAYERS | 2 |

| 2 WAY RADIOS | 2 |

+----------------------+-------+

We can use the depth value to indent our category names with the CONCAT and REPEAT string functions:

SELECT CONCAT( REPEAT(' ', COUNT(https://www.360docs.net/doc/0818574078.html,) - 1), https://www.360docs.net/doc/0818574078.html,) AS name FROM nested_category AS node,

nested_category AS parent

WHERE node.lft BETWEEN parent.lft AND parent.rgt

GROUP BY https://www.360docs.net/doc/0818574078.html,

ORDER BY node.lft;

+-----------------------+

| name |

+-----------------------+

| ELECTRONICS |

| TELEVISIONS |

| TUBE |

| LCD |

| PLASMA |

| PORTABLE ELECTRONICS |

| MP3 PLAYERS |

| FLASH |

| CD PLAYERS |

| 2 WAY RADIOS |

+-----------------------+

Of course, in a client-side application you will be more likely to use the depth value directly to display your hierarchy. Web developers could loop through the tree, adding

  • and
      tags as the depth number increases and decreases.

      Depth of a Sub-Tree

      When we need depth information for a sub-tree, we cannot limit either the node or parent tables in our self-join because it will corrupt our results. Instead, we add a third self-join, along with a sub-query to determine the depth that will be the new starting point for our sub-tree:

      SELECT https://www.360docs.net/doc/0818574078.html,, (COUNT(https://www.360docs.net/doc/0818574078.html,) - (sub_tree.depth + 1)) AS depth FROM nested_category AS node,

      nested_category AS parent,

      nested_category AS sub_parent,

      (

      SELECT https://www.360docs.net/doc/0818574078.html,, (COUNT(https://www.360docs.net/doc/0818574078.html,) - 1) AS depth

      FROM nested_category AS node,

      nested_category AS parent

      WHERE node.lft BETWEEN parent.lft AND parent.rgt

      AND https://www.360docs.net/doc/0818574078.html, = 'PORTABLE ELECTRONICS'

      GROUP BY https://www.360docs.net/doc/0818574078.html,

      ORDER BY node.lft

      )AS sub_tree

      WHERE node.lft BETWEEN parent.lft AND parent.rgt

      AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt

      AND sub_https://www.360docs.net/doc/0818574078.html, = sub_https://www.360docs.net/doc/0818574078.html,

      GROUP BY https://www.360docs.net/doc/0818574078.html,

      ORDER BY node.lft;

      +----------------------+-------+

      | name | depth |

      +----------------------+-------+

      | PORTABLE ELECTRONICS | 0 |

      | MP3 PLAYERS | 1 |

      | FLASH | 2 |

      | CD PLAYERS | 1 |

      | 2 WAY RADIOS | 1 |

      +----------------------+-------+

      This function can be used with any node name, including the root node. The depth values are always relative to the named node.

      Find the Immediate Subordinates of a Node

      Imagine you are showing a category of electronics products on a retailer web site. When a user clicks on a category, you would want to show the products of that category, as well as list its immediate sub-categories, but not the entire tree of categories beneath it. For this, we need to show the node and its immediate sub-nodes, but no further down the tree. For example, when showing the PORTABLE ELECTRONICS category, we will want to show MP3 PLAYERS, CD PLAYERS, and 2 WAY RADIOS, but not FLASH.

      This can be easily accomplished by adding a HAVING clause to our previous query:

      SELECT https://www.360docs.net/doc/0818574078.html,, (COUNT(https://www.360docs.net/doc/0818574078.html,) - (sub_tree.depth + 1)) AS depth

      FROM nested_category AS node,

      nested_category AS parent,

      nested_category AS sub_parent,

      (

      SELECT https://www.360docs.net/doc/0818574078.html,, (COUNT(https://www.360docs.net/doc/0818574078.html,) - 1) AS depth

      FROM nested_category AS node,

      nested_category AS parent

      WHERE node.lft BETWEEN parent.lft AND parent.rgt

      AND https://www.360docs.net/doc/0818574078.html, = 'PORTABLE ELECTRONICS'

      GROUP BY https://www.360docs.net/doc/0818574078.html,

      ORDER BY node.lft

      )AS sub_tree

      WHERE node.lft BETWEEN parent.lft AND parent.rgt

      AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt

      AND sub_https://www.360docs.net/doc/0818574078.html, = sub_https://www.360docs.net/doc/0818574078.html,

      GROUP BY https://www.360docs.net/doc/0818574078.html,

      HAVING depth <= 1

      ORDER BY node.lft;

      +----------------------+-------+

      | name | depth |

      +----------------------+-------+

      | PORTABLE ELECTRONICS | 0 |

      | MP3 PLAYERS | 1 |

      | CD PLAYERS | 1 |

      | 2 WAY RADIOS | 1 |

      +----------------------+-------+

      If you do not wish to show the parent node, change the HAVING depth <= 1 line to HAVING depth = 1.

      Aggregate Functions in a Nested Set

      Let's add a table of products that we can use to demonstrate aggregate functions with:

      CREATE TABLE product(

      product_id INT AUTO_INCREMENT PRIMARY KEY,

      name VARCHAR(40),

      category_id INT NOT NULL

      );

      INSERT INTO product(name, category_id) VALUES('20" TV',3),('36" TV',3),

      ('Super-LCD 42"',4),('Ultra-Plasma 62"',5),('Value Plasma 38"',5), ('Power-MP3 5gb',7),('Super-Player 1gb',8),('Porta CD',9),('CD To

      go!',9),

      ('Family Talk 360',10);

      SELECT * FROM product;

      +------------+-------------------+-------------+

      | product_id | name | category_id |

      +------------+-------------------+-------------+

      | 1 | 20" TV | 3 |

      | 2 | 36" TV | 3 |

      | 3 | Super-LCD 42" | 4 |

      | 4 | Ultra-Plasma 62" | 5 |

      | 5 | Value Plasma 38" | 5 |

      | 6 | Power-MP3 128mb | 7 |

      | 7 | Super-Shuffle 1gb | 8 |

      | 8 | Porta CD | 9 |

      | 9 | CD To go! | 9 |

      | 10 | Family Talk 360 | 10 |

      +------------+-------------------+-------------+

      Now let's produce a query that can retrieve our category tree, along with a product count for each category:

      SELECT https://www.360docs.net/doc/0818574078.html,, COUNT(https://www.360docs.net/doc/0818574078.html,)

      FROM nested_category AS node ,

      nested_category AS parent,

      product

      WHERE node.lft BETWEEN parent.lft AND parent.rgt

      AND node.category_id = product.category_id

      GROUP BY https://www.360docs.net/doc/0818574078.html,

      ORDER BY node.lft;

      +----------------------+---------------------+

      | name | COUNT(https://www.360docs.net/doc/0818574078.html,) |

      +----------------------+---------------------+

      | ELECTRONICS | 10 |

      | TELEVISIONS | 5 |

      | TUBE | 2 |

      | LCD | 1 |

      | PLASMA | 2 |

      | PORTABLE ELECTRONICS | 5 |

      | MP3 PLAYERS | 2 |

      | FLASH | 1 |

      | CD PLAYERS | 2 |

      | 2 WAY RADIOS | 1 |

      +----------------------+---------------------+

      This is our typical whole tree query with a COUNT and GROUP BY added, along with a reference to the product table and a join between the node and product table in the WHERE clause. As you can see, there is a count for each category and the count of subcategories is reflected in the parent categories.

      Adding New Nodes

      Now that we have learned how to query our tree, we should take a look at how to update our tree by adding a new node. Let's look at our nested set diagram again:

      If we wanted to add a new node between the TELEVISIONS and PORTABLE ELECTRONICS nodes, the new node would have lft and rgt values of 10 and 11, and all nodes to its right would have their lft and rgt values increased by two. We would then add the new node with the appropriate lft and rgt values. While this can be done with a stored procedure in MySQL 5, I will assume for the moment that most readers are using 4.1, as it is the latest stable version, and I will isolate my queries with a LOCK TABLES statement instead:

      LOCK TABLE nested_category WRITE;

      SELECT @myRight := rgt FROM nested_category

      WHERE name = 'TELEVISIONS';

      UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myRight; UPDATE nested_category SET lft = lft + 2 WHERE lft > @myRight;

      INSERT INTO nested_category(name, lft, rgt) VALUES('GAME CONSOLES',

      @myRight + 1, @myRight + 2);

      UNLOCK TABLES;

      We can then check our nesting with our indented tree query:

      SELECT CONCAT( REPEAT( ' ', (COUNT(https://www.360docs.net/doc/0818574078.html,) - 1) ), https://www.360docs.net/doc/0818574078.html,) AS name FROM nested_category AS node,

      nested_category AS parent

      WHERE node.lft BETWEEN parent.lft AND parent.rgt

      GROUP BY https://www.360docs.net/doc/0818574078.html,

      ORDER BY node.lft;

      +-----------------------+

      | name |

      +-----------------------+

      | ELECTRONICS |

      | TELEVISIONS |

      | TUBE |

      | LCD |

      | PLASMA |

      | GAME CONSOLES |

      | PORTABLE ELECTRONICS |

      | MP3 PLAYERS |

      | FLASH |

      | CD PLAYERS |

      | 2 WAY RADIOS |

      +-----------------------+

      If we instead want to add a node as a child of a node that has no existing children, we need to modify our procedure slightly. Let's add a new FRS node below the 2 WAY RADIOS node:

      LOCK TABLE nested_category WRITE;

      SELECT @myLeft := lft FROM nested_category

      二叉树的存储表示

      二叉树的存储表示 1二叉树的顺序存储表示 2二叉树的链式存储表示 3三叉链表 1二叉树的顺序存储表示 二叉树的顺序存储结构的定义如下: #define MAXSIZE = 100; //暂定二叉树中节点数的最大值为100 Typedef struct { ElemType *data ; //存储空间基址(初始化时分配空间) Int nodeNum ; //二叉树中节点数 }SqBiTree ; //二叉树的顺序存储结构 为了能在存储结构中反映出节点之间的逻辑关系,必须将二叉树中节点依照一定规律安排在这组存储单元中。对于完全二叉树,只要从根起按层序存储即可。 显然,这种顺序存储结构仅适用于完全二叉树。因为,在最坏的情况下,一个深度为 k 且只有 k 个结点的单支树(树中不存在度为 2 的结点)却需要长度为2k -1的一维数组。 二叉树的顺序存储图如图1所示: 2 6 320 116 5402 106 543216 (a )满二叉树(b )一般二叉树 图1 顺序存储

      2二叉树的链式存储表示 二叉树有不同的链式结构,其中最常用的是二叉链表与三叉链表。二叉链表的结点形式如表1所示: 表1链式存储 date域:称为数据域,用于存储二叉树结点中的数据元素, 1child域:称为左孩子指针域,用于存放指向本结点左孩子的指针(左指针)。 rchild域:称为右孩子指针域,用于存放指向本结点右孩子的指针(右指针)二叉链表中的所有存储结点通过它们的左、右指针的链接而形成一个整体。 根指针:每个二叉链表还必须有一个指向根结点的指针。根指针具有标识二叉链表的作用,对二叉链表的访问能从根指针开始。 图2中(a)(b)表示一棵二叉树及其二叉链表。值得注意的是,二叉链表中每个存储结点的每个指针域必须有一个值,这个值或者是指向该结点的一个孩子的指针,或者是空指针NULL。 二叉链表的类型定义如下: Typedef struct btnode *bitreptr; Struct btnode { Datatype data; Bitreptr lchild,rchild; }; Bitreptr root; 若二叉树为空,则root=NULL。若某结点的某个孩子不存在,则相应的指针为空。具有n个结点的二叉树中,一共有2n个指针域,其中只有n-1个用来指向结点的的左右孩子,其余的n+1个指针域为NULL。 在二叉链表这种存储结构上,二叉树的多数基本运算如求根,求左、右孩子等很容易实现。但求双亲运算PARENT(BT,X)的实现却比较麻烦,而且其时间性能不高。

      数据结构树和二叉树实验报告

      《数据结构》课程实验报告 实验名称树和二叉树实验序号 5 实验日期 姓名院系班级学号 专业指导教师成绩 教师评语 一、实验目的和要求 (1)掌握树的相关概念,包括树、结点的度、树的度、分支结点、叶子结点、儿子结点、双亲结点、树 的深度、森林等定义。 (2)掌握树的表示,包括树形表示法、文氏图表示法、凹入表示法和括号表示法等。 (3)掌握二叉树的概念,包括二叉树、满二叉树和完全二叉树的定义。 (4)掌握二叉树的性质。 (5)重点掌握二叉树的存储结构,包括二叉树顺序存储结构和链式存储结构。 (6)重点掌握二叉树的基本运算和各种遍历算法的实现。 (7)掌握线索二叉树的概念和相关算法的实现。 (8)掌握哈夫曼树的定义、哈夫曼树的构造过程和哈夫曼编码产生方法。 (9)掌握并查集的相关概念和算法。 (10)灵活掌握运用二叉树这种数据结构解决一些综合应用问题。 二、实验项目摘要 1.编写一程序,实现二叉树的各种基本运算,并在此基础上设计一个主程序完成如下功能: (1)输出二叉树b; (2)输出H结点的左、右孩子结点值; (3)输出二叉树b的深度; (4)输出二叉树b的宽度; (5)输出二叉树b的结点个数; (6)输出二叉树b的叶子结点个数。 2.编写一程序,实现二叉树的先序遍历、中序遍历和后序遍历的各种递归和非递归算法,以及层次遍历的算法。 三、实验预习内容 二叉树存储结构,二叉树基本运算(创建二叉树、寻找结点、找孩子结点、求高度、输出二叉树)

      三、实验结果与分析 7-1 #include #include #define MaxSize 100 typedef char ElemType; typedef struct node { ElemType data; struct node *lchild; struct node *rchild; } BTNode; void CreateBTNode(BTNode *&b,char *str) { BTNode *St[MaxSize],*p=NULL; int top=-1,k,j=0; char ch; b=NULL; ch=str[j]; while (ch!='\0') { switch(ch) { case '(':top++;St[top]=p;k=1; break; case ')':top--;break; case ',':k=2; break; default:p=(BTNode *)malloc(sizeof(BTNode)); p->data=ch;p->lchild=p->rchild=NULL; if (b==NULL) b=p; else { switch(k) { case 1:St[top]->lchild=p;break; case 2:St[top]->rchild=p;break; } } } j++; ch=str[j]; }

      《数据结构》习题集:_树和叉树

      第6章树和二叉树 一、选择题 1.有一“遗传”关系,设x是y的父亲,则x可以把它的属性遗传给y,表示该遗传关系最适合的数据结构是( B ) A、向量 B、树 C、图 D、二叉树 2.树最适合用来表示( B ) A、有序数据元素 B、元素之间具有分支层次关系的数据 C、无序数据元素 D、元素之间无联系的数据 3.树B 的层号表示为1a,2b,3d,3e,2c,对应于下面选择的( C ) A、1a(2b(3d,3e),2c) B、a(b(D,e),c) C、a(b(d,e),c) D、a(b,d(e),c) 4.对二叉树的结点从1 开始连续编号,要求每个结点的编号大于其左、右孩子的编号,同一结点的左右孩子中, 其左孩子的编号小于其右孩子的编号,则可采用( C )次序的遍历实现二叉树的结点编号。 A、先序 B、中序 C、后序 D、从根开始按层次遍历 5.按照二叉树的定义,具有3 个结点的二叉树有(C )种。 A、3 B、4 C、5 D、6 6.在一棵有n个结点的二叉树中,若度为2的结点数为n2,度为1的结点数为n1,度为0的结点数为n0,则树的最大高 度为( E ),其叶结点数为( H );树的最小高度为( B ),其叶结点数为( G );若采用链表存储结构,则有( I )个空链域。 log+1 C、log2n D、n A、n/2 B、??n2 E、n0+n1+n2 F、n1+n2 G、n2+1 H、1 I、n+1 J、n1K、n2L、n1+1 7.对一棵满二叉树,m 个树叶,n 个结点,深度为h,则( D ) A、n=m+h B、h+m=2n C、m=h-1 D、n=2h-1 8.设高度为h 的二叉树中只有度为0 和度为2 的结点,则此类二叉树中所包含的结点数至少为( B ),至多 为(D )。 A、2h B、2h-1 C、2h-1 D、2h-1 9.在一棵二叉树上第5 层的结点数最多为(B)(假设根结点的层数为1) A、8 B、16 C、15 D、32 10.深度为5 的二叉树至多有( C )个结点。 A、16 B、32 C、31 D、10 11.一棵有124 个叶结点的完全二叉树,最多有(B )个结点 A、247 B、248 C、249 D、250 12.含有129 个叶子结点的完全二叉树,最少有( D )个结点 A、254 B、255 C、256 D、257 13.假定有一棵二叉树,双分支结点数为15,单分支结点数为30,则叶子结点数为( B )个。 A、15 B、16 C、17 D、47 14.用顺序存储的方法将完全二叉树中所有结点逐层存放在数组R[1…n]中,结点R[i]若有左子树,则左子树是结 点( B )。 A、R[2i+1] B、R[2i] C、R[i/2] D、R[2i-1]

      数据结构二叉树实验报告

      实验三二叉树的遍历 一、实验目的 1、熟悉二叉树的结点类型和二叉树的基本操作。 2、掌握二叉树的前序、中序和后序遍历的算法。 3、加深对二叉树的理解,逐步培养解决实际问题的编程能力。 二、实验环境 运行C或VC++的微机。 三、实验内容 1、依次输入元素值,以链表方式建立二叉树,并输出结点的值。 2、分别以前序、中序和后序遍历二叉树的方式输出结点内容。 四、设计思路 1. 对于这道题,我的设计思路是先做好各个分部函数,然后在主函数中进行顺序排列,以此完成实验要求 2.二叉树采用动态数组 3.二叉树运用9个函数,主要有主函数、构建空二叉树函数、建立二叉树函数、访问节点函数、销毁二叉树函数、先序函数、中序函数、后序函数、范例函数,关键在于访问节点 五、程序代码 #include #include #include #define OK 1 #define ERROR 0 typedef struct TNode//结构体定义 {

      int data; //数据域 struct TNode *lchild,*rchild; // 指针域包括左右孩子指针 }TNode,*Tree; void CreateT(Tree *T)//创建二叉树按,依次输入二叉树中结点的值 { int a; scanf("%d",&a); if(a==00) // 结点的值为空 *T=NULL; else // 结点的值不为空 { *T=(Tree)malloc(sizeof(TNode)); if(!T) { printf("分配空间失败!!TAT"); exit(ERROR); } (*T)->data=a; CreateT(&((*T)->lchild)); // 递归调用函数,构造左子树 CreateT(&((*T)->rchild)); // 递归调用函数,构造右子树 } } void InitT(Tree *T)//构建空二叉树 { T=NULL; } void DestroyT(Tree *T)//销毁二叉树 { if(*T) // 二叉树非空 { DestroyT(&((*T)->lchild)); // 递归调用函数,销毁左子树 DestroyT(&((*T)->rchild)); // 递归调用函数,销毁右子树 free(T); T=NULL; } } void visit(int e)//访问结点 { printf("%d ",e); }

      数据结构实验指导书 二叉树两种存储结构的应用

      一、实验名称:二叉树两种存储结构的应用 二、实验目的和要求: 1.掌握二叉树的遍历思想及二叉树的存储实现。 2.掌握二叉树的基本操作:建立二叉树、二叉树的遍历 3.选择一种形式完成二叉树的显示 4.掌握二叉树的常见算法的程序实现 5.实验报告中要写出测试数据、错误分析以及收获 三、上机实验内容一:二叉树的建立及相关算法的实现 1.完成的功能包括如下几点: ①编程实现建立一棵二叉树,然后对其进行先序、中序和后序遍历。 分析:将要输入的二叉树按照其对应的完全二叉树的顺序输入,若当前位置不存在结点则输入@ ②显示二叉树 ③求二叉树的高度及二叉树的叶子个数等等 ④在主函数中设计一个简单的菜单,分别调试上述算法 四、上机实验内容二:哈夫曼编码/译码系统 1.要求编写一程序模拟传输过程,实现在发送前将要发送的字符信息进行编码,然后进行发送,接收后将传来的数据进行译码,即将信息还原成发送前的字符信息。 2.设计分析 在本例中的算法主要有:哈夫曼树的建立;哈夫曼编码的生成;对编码信息的翻译。要求设置发送者和接收者两个功能。 发送者的功能包括: ①输入待传送的字符信息;②统计字符信息中出现的字符类数和各字符出现的次数(频率);③根据字符的种类数和各字符出现的次数建立哈夫曼树;④利用以上哈夫曼树求出各字符的哈夫曼编码;⑤将字符信息转换成对应的编码信息进行传送。 接收者的功能包括: ①接收发送者传送来的编码信息;②利用上述哈夫曼树对编码进行翻译,即将编码信息还原成发送前的字符信息。 3.结点的类型定义 ①哈夫曼树的存储结构类型定义为:

      typedef struct { char data; /*编码对应的字符*/ int weight; /*结点的权值*/ int lchild,rchild,parent;/*左右孩子及双亲的下标*/ }HTNode; ②哈夫曼编码的存储结构类型定义为: typedef struct { char bits[N]; /*存放哈夫曼编码的字符数组*/ int start; /*记录编码的起始位置,因为每种字符的编码长度不同*/ }HCode; 说明:只占用2个课内学时,学生可利用开放实验室利用课余时间完成本次实验内容。

      第六章树和二叉树习题数据结构

      习题六树和二叉树 一、单项选择题 1.以下说法错误的是 ( ) A.树形结构的特点是一个结点可以有多个直接前趋 B.线性结构中的一个结点至多只有一个直接后继 C.树形结构可以表达(组织)更复杂的数据 D.树(及一切树形结构)是一种"分支层次"结构 E.任何只含一个结点的集合是一棵树 2.下列说法中正确的是 ( ) A.任何一棵二叉树中至少有一个结点的度为2 B.任何一棵二叉树中每个结点的度都为2 C.任何一棵二叉树中的度肯定等于2 D.任何一棵二叉树中的度可以小于2 3.讨论树、森林和二叉树的关系,目的是为了() A.借助二叉树上的运算方法去实现对树的一些运算 B.将树、森林按二叉树的存储方式进行存储 C.将树、森林转换成二叉树 D.体现一种技巧,没有什么实际意义 4.树最适合用来表示 ( ) A.有序数据元素 B.无序数据元素 C.元素之间具有分支层次关系的数据 D.元素之间无联系的数据 5.若一棵二叉树具有10个度为2的结点,5个度为1的结点,则度为0的结点个数是()A.9 B.11 C.15 D.不确定 6.设森林F中有三棵树,第一,第二,第三棵树的结点个数分别为M1,M2和M3。与森林F对应的二叉树根结点的右子树上的结点个数是()。 A.M1 B.M1+M2 C.M3 D.M2+M3 7.一棵完全二叉树上有1001个结点,其中叶子结点的个数是() A. 250 B. 500 C.254 D.505 E.以上答案都不对 8. 设给定权值总数有n 个,其哈夫曼树的结点总数为( ) A.不确定 B.2n C.2n+1 D.2n-1 9.二叉树的第I层上最多含有结点数为() A.2I B. 2I-1-1 C. 2I-1 D.2I -1 10.一棵二叉树高度为h,所有结点的度或为0,或为2,则这棵二叉树最少有( )结点A.2h B.2h-1 C.2h+1 D.h+1 11. 利用二叉链表存储树,则根结点的右指针是()。 A.指向最左孩子 B.指向最右孩子 C.空 D.非空 14.在二叉树结点的先序序列,中序序列和后序序列中,所有叶子结点的先后顺序()A.都不相同 B.完全相同 C.先序和中序相同,而与后序不同 D.中序和后序相同,而与先序不同 15.在完全二叉树中,若一个结点是叶结点,则它没()。 A.左子结点 B.右子结点 C.左子结点和右子结点 D.左子结点,右子结点和兄弟结点 16.在下列情况中,可称为二叉树的是()

      目前最完整的数据结构1800题包括完整答案树和二叉树答案

      第6章树和二叉树 部分答案解释如下。 12. 由二叉树结点的公式:n=n0+n1+n2=n0+n1+(n0-1)=2n0+n1-1,因为n=1001,所以1002=2n0+n1,在完全二叉树树中,n1只能取0或1,在本题中只能取0,故n=501,因此选E。 42.前序序列是“根左右”,后序序列是“左右根”,若要这两个序列相反,只有单支树,所以本题的A和B均对,单支树的特点是只有一个叶子结点,故C是最合适的,选C。A或B 都不全。由本题可解答44题。 47. 左子树为空的二叉树的根结点的左线索为空(无前驱),先序序列的最后结点的右线索为空(无后继),共2个空链域。 52.线索二叉树是利用二叉树的空链域加上线索,n个结点的二叉树有n+1个空链域。 部分答案解释如下。 6.只有在确定何序(前序、中序、后序或层次)遍历后,遍历结果才唯一。 19.任何结点至多只有左子树的二叉树的遍历就不需要栈。 24. 只对完全二叉树适用,编号为i的结点的左儿子的编号为2i(2i<=n),右儿子是2i+1(2i+1<=n) 37. 其中序前驱是其左子树上按中序遍历的最右边的结点(叶子或无右子女),该结点无右孩子。 38 . 新插入的结点都是叶子结点。 42. 在二叉树上,对有左右子女的结点,其中序前驱是其左子树上按中序遍历的最右边的结点(该结点的后继指针指向祖先),中序后继是其右子树上按中序遍历的最左边的结点(该结点的前驱指针指向祖先)。 44.非空二叉树中序遍历第一个结点无前驱,最后一个结点无后继,这两个结点的前驱线索和后继线索为空指针。 三.填空题

      1.(1)根结点(2)左子树(3)右子树 2.(1)双亲链表表示法(2)孩子链表表示法(3)孩 子兄弟表示法 3.p->lchild==null && p->rchlid==null 4.(1) ++a*b3*4-cd (2)18 5.平衡 因子 6. 9 7. 12 8.(1)2k-1 (2)2k-1 9.(1)2H-1 (2)2H-1 (3)H=?log2N?+1 10. 用顺序存储二叉树时,要按完全二叉树的形式存储,非完全二叉树存储时,要加“虚结 点”。设编号为i和j的结点在顺序存储中的下标为s 和t ,则结点i和j在同一层上的条 件是?log2s?=?log2t?。 11. ?log2i?=?log2j?12.(1)0 (2)(n-1)/2 (3)(n+1)/2 (4) ?log2n?+1 13.n 14. N2+1 15.(1) 2K+1-1 (2) k+1 16. ?N/2? 17. 2k-2 18. 64 19. 99 20. 11 21.(1) n1-1 (2)n2+n3 22.(1)2k-2+1(第k层1个结点,总结点个数是2H-1,其双亲是2H-1/2=2k-2)(2) ?log2i?+1 23.69 24. 4 25.3h-1 26. ?n/2? 27. ?log2k?+1 28.(1)完全二叉树 (2)单枝树,树中任一结点(除最后一个结点是叶子外),只有左子女或 只有右子女。 29.N+1 30.(1) 128(第七层满,加第八层1个) (2) 7 31. 0至多个。任意二叉树,度为1的结点个数没限制。只有完全二叉树,度为1的结点个 数才至多为1。 32.21 33.(1)2 (2) n-1 (3) 1 (4) n (5) 1 (6) n-1 34.(1) FEGHDCB (2)BEF(该二叉树转换成森林,含三棵树,其第一棵树的先根次序是 BEF) 35.(1)先序(2)中序 36. (1)EACBDGF (2)2 37.任何结点至多只有右子女 的二叉树。 38.(1)a (2) dbe (3) hfcg 39.(1) . (2) ...GD.B...HE..FCA 40.DGEBFCA 41.(1)5 (2)略 42.二叉排序树 43.二叉树 44. 前序 45.(1)先根次序(2)中根次序46.双亲的右子树中最左下的叶子结点47.2 48.(n+1)/2 49.31(x的后继是经x的双亲y的右子树中最左下的叶结点) 50.(1)前驱 (2)后 继 51.(1)1 (2)y^.lchild (3)0 (4)x (5)1 (6) y (7)x(编者注:本题按 中序线索化) 52.带权路径长度最小的二叉树,又称最优二叉树 53.69 54.(1)6 (2)261 55.(1)80 (2)001(不唯一)56.2n0-1 57.本题①是表达式求值,②是在二叉排序树中删除值为x的结点。首先查找x,若没有x, 则结束。否则分成四种情况讨论:x结点有左右子树;只有左子树;只有右子树和本身是叶 子。 (1)Postoder_eval(t^.Lchild) (2) Postorder_eval(t^.Rchild) (3)ERROR(无此运 算符)(4)A (5)tempA^.Lchild (6)tempA=NULL(7)q^.Rchild (8)q (9)tempA^.Rchild (10)tempA^.Item

      树和二叉树实验报告

      树和二叉树 一、实验目的 1.掌握二叉树的结构特征,以及各种存储结构的特点及适用范围。 2.掌握用指针类型描述、访问和处理二叉树的运算。 二、实验要求 1.认真阅读和掌握本实验的程序。 2.上机运行本程序。 3.保存和打印出程序的运行结果,并结合程序进行分析。 4.按照二叉树的操作需要,重新改写主程序并运行,打印出文件清单和运 行结果。 三、实验内容 1.输入字符序列,建立二叉链表。 2.按先序、中序和后序遍历二叉树(递归算法)。 3.按某种形式输出整棵二叉树。 4.求二叉树的高度。 5.求二叉树的叶节点个数。 6.交换二叉树的左右子树。 7.借助队列实现二叉树的层次遍历。 8.在主函数中设计一个简单的菜单,分别调试上述算法。 为了实现对二叉树的有关操作,首先要在计算机中建立所需的二叉树。建立二叉树有各种不同的方法。一种方法是利用二叉树的性质5来建立二叉树,输入数据时要将节点的序号(按满二叉树编号)和数据同时给出:(序号,数据元素0)。另一种方法是主教材中介绍的方法,这是一个递归方法,与先序遍历有点相似。数据的组织是先序的顺序,但是另有特点,当某结点的某孩子为空时以字符“#”来充当,也要输入。若当前数据不为“#”,则申请一个结点存入当前数据。递归调用建立函数,建立当前结点的左右子树。 四、解题思路 1、先序遍历:○1访问根结点,○2先序遍历左子树,○3先序遍历右子树 2、中序遍历:○1中序遍历左子树,○2访问根结点,○3中序遍历右子树 3、后序遍历:○1后序遍历左子树,○2后序遍历右子树,○3访问根结点 4、层次遍历算法:采用一个队列q,先将二叉树根结点入队列,然后退队列,输出该结点;若它有左子树,便将左子树根结点入队列;若它有右子树,便将右子树根结点入队列,直到队列空为止。因为队列的特点是先进后出,所以能够达到按层次遍历二叉树的目的。 五、程序清单 #include #include #define M 100

      二叉树的顺序存储结构

      #include #include #define VirNode ' ' /* 用空格符描述“虚结点”*/ #define MAXSIZE 64 typedef char ElemType; typedefElemTypeSqBitTree[MAXSIZE]; void crebitree(SqBitTreeBT,int n) /* n为二叉树真实结点数*/ { inti,j,m; i=1; m=0; while(m

      { inti,n=0; for(i=1;i<=BT[0]/2;i++) if(BT[i]!=VirNode&&BT[2*i]==VirNode&&BT[2*i+1]==VirNode) n++; for(;i<=BT[0];i++) if(BT[i]!=VirNode) n++; return n; } int countn1(SqBitTree BT) { inti,n=0; for(i=1;i<=BT[0]/2;i++) if(BT[i]!=VirNode&&(BT[2*i]==VirNode&&BT[2*i+1]!=VirNode|| BT[2*i]!=VirNode&&BT[2*i+1]==VirNode)) n++; return n; } int countn2(SqBitTree BT) { inti,n=0; for(i=1;i<=BT[0]/2;i++) if(BT[i]!=VirNode&&BT[2*i]!=VirNode&&BT[2*i+1]!=VirNode) n++; return n; } //主函数 void main() { SqBitTree T; int n; crebitree(T,5); levellist(T); printf("High=%d\n",high(T)); levellist(T); printf("n2=%d\n",countn2(T)); getch(); }

      数据结构树和二叉树习题

      树与二叉树 一.选择题 1.假定在一棵二叉树中,双分支结点数为15,单分支结点数为30个,则叶子结 点数为()个。 A.15B.16C.17D.47 2.按照二叉树的定义,具有3个结点的不同形状的二叉树有()种。 A. 3 B. 4 C. 5 D. 6 3.按照二叉树的定义,具有3个不同数据结点的不同的二叉树有()种。 A. 5 B. 6 C. 30 D. 32 4.深度为5的二叉树至多有()个结点。1 A. 16 B. 32 C. 31 D. 10 5.设高度为h的二叉树上只有度为0和度为2的结点,则此类二叉树中所包含的 结点数至少为()。 A. 2h B. 2h-1 C. 2h+1 D. h+1 6.对一个满二叉树2,m个树叶,n个结点,深度为h,则()。 A. n=h+m3 B. h+m=2n C. m=h-1 D. n=2 h-1 1深度为n的二叉树结点至多有2n-1 2满二叉树是除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树7.任何一棵二叉树的叶结点在先序.中序和后序遍历序列中的相对次序()。 A.不发生改变 B.发生改变 C.不能确定 D.以上都不对 8.如果某二叉树的前根次序遍历结果为stuwv,中序遍历为uwtvs,那么该二叉 树的后序为()。 A. uwvts B. vwuts C. wuvts D. wutsv 9.某二叉树的前序遍历结点访问顺序是abdgcefh,中序遍历的结点访问顺序是 dgbaechf,则其后序遍历的结点访问顺序是()。 A. bdgcefha B. gdbecfha C. bdgaechf D. gdbehfca 10.在一非空二叉树的中序遍历序列中,根结点的右边()。 A. 只有右子树上的所有结点 B. 只有右子树上的部分结点 C. 只有左子树上的部分结点 D. 只有左子树上的所有结点 11.树的基本遍历策略可分为先根遍历和后根遍历;二叉树的基本遍历策略可分为 先序遍历.中序遍历和后序遍历。这里,我们把由树转化得到的二叉树4叫做这棵数对应的二叉树。结论()是正确的。 A.树的先根遍历序列与其对应的二叉树的先序遍历序列相同 B.树的后根遍历序列与其对应的二叉树的后序遍历序列相同 3对于深度为h的满二叉树,n=20+21+…+2h-1=2h-1,m=2h-1。故而n=h+m。 4树转化为二叉树的基本方法是把所有兄弟结点都用线连起来,然后去掉双亲到子女的连线,只留下双亲到第一个子女的连线。因此原来的兄弟关系就变为双亲与右孩子的关系。 1/ 9

      二叉树的建立和遍历的实验报告doc

      二叉树的建立和遍历的实验报告 篇一:二叉树的建立及遍历实验报告 实验三:二叉树的建立及遍历 【实验目的】 (1)掌握利用先序序列建立二叉树的二叉链表的过程。 (2)掌握二叉树的先序、中序和后序遍历算法。 【实验内容】 1. 编写程序,实现二叉树的建立,并实现先序、中序和后序遍历。 如:输入先序序列abc###de###,则建立如下图所示的二叉树。 并显示其先序序列为:abcde 中序序列为:cbaed 后序序列为:cbeda 【实验步骤】 1.打开VC++。 2.建立工程:点File->New,选Project标签,在列表中选Win32 Console Application,再在右边的框里为工程起好名字,选好路径,点OK->finish。至此工程建立完毕。 3.创建源文件或头文件:点File->New,选File标签,在列表里选C++ Source File。给文件起好名字,选好路径,点OK。至此一个源文件就被添加到了你刚创建的工程之中。

      4.写好代码 5.编译->链接->调试 #include #include #define OK 1 #define OVERFLOW -2 typedef int Status; typedef char TElemType; typedef struct BiTNode { TElemType data; struct BiTNode *lchild, *rchild; }BiTNode,*BiTree; Status CreateBiTree(BiTree &T) { TElemType ch; scanf("%c",&ch); if (ch=='#') T= NULL; else { if (!(T = (BiTNode *)malloc(sizeof(BiTNode))))

      实验五--二叉树的存储结构和基本操作

      实验五二叉树的存储表示和基本操作 实验内容 1. 二叉树的二叉链表的存储结构 —————二叉树的二叉链表存储表示———————— typedef struct node { ElemType data; /*数据元素*/ struct node *lchild; /*指向左孩子*/ struct node *rchild; /*指向右孩子*/ } BTNode; 2. 二叉树的基本操作 (1)创建操作:创建一棵二叉树。 (2)查找操作:查找二叉树中值为x的结点。 (3)查找左孩子操作:查找二叉树中值为x的结点的左孩子。 (4)查找右孩子操作:查找二叉树中值为x的结点的右孩子。 (5)求深度操作:求二叉树的深度。 (6)求宽度操作:求二叉树的宽度。 (7)求结点个数操作:求二叉树的结点个数。 (8)求叶子结点个数操作:求二叉树的叶子结点个数。 (9)输出操作:以括号表示法输出二叉树。 3. 链式队列操作实现的步骤 (1)实现将链式队列的存储结构和基本操作程序代码。 (2)实现main主函数。 4.程序代码完整清单 #include #include #define MaxSize 100 typedef char ElemType; typedef struct node { ElemType data; /*数据元素*/ struct node *lchild; /*指向左孩子*/ struct node *rchild; /*指向右孩子*/ } BTNode; //基本操作函数声明 void CreateBTNode(BTNode *&b,char *str); /*创建一棵二叉树*/ BTNode *FindNode(BTNode *b,ElemType x); /*查找二叉树的结点*/ BTNode *LchildNode(BTNode *p); /*查找二叉树结点的左孩子*/ BTNode *RchildNode(BTNode *p); /*查找二叉树结点的右孩子*/ int BTNodeDepth(BTNode *b); /*求二叉树的深度*/

      二叉树实验报告及代码

      重庆交通大学综合性设计性实验报告 姓名姚远学号 631106060113 班级:计信息一班 实验项目名称:二叉树 实验项目性质:设计性实验 实验所属课程:数据结构 实验室(中心): 407机房 指导教师:鲁云平 实验完成时间: 2013 年 5 月 10 日

      一、实验目的 1. 建立二叉树 2. 计算结点所在的层次 3.统计结点数量和叶结点数量 4.计算二叉树的高度 5.计算结点的度 6.找结点的双亲和子女 7.二叉树的遍历 8.二叉树的输出等等 二、实验内容及要求 1.二叉树的结点结构,二叉树的存储结构由学生自由选择和设定 2.实验完成后上交打印的实验报告,报告内容与前面所给定的实验模板相同 3.将实验报告电子版和源代码在网络教学平台提交 三、实验设备及软件 VISUAL C++软件 四、设计方案 ㈠题目(老师给定或学生自定) 二叉树的应用 ㈡设计的主要思路 在计算机科学中,二叉树是每个结点最多有两个子树的有序树。通常子树的根被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用作二叉查找树和二叉堆或是二叉排序树。二叉树的每个结点至多只有二棵子树(不存在出度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2的i -1次方个结点;深度为k的二叉树至多有2^(k) -1个结点;对任何一棵二叉树T,如果其终端结点数(即叶子结点数)为n0,出度为2的结点数为n2,则n0 =n2 + 1。 ㈢主要功能

      实现二叉树的各项操作。 五、主要代码 #include #include #include typedef struct BinTreeNode //二叉树结点类定义 { char data; //数据域 BinTreeNode *leftChild, *rightChild; //左子女、右子女链域 }*BTree; BinTreeNode *p,*q,*f; int NodeNum,Leaf; int NodeDu,nodeloc=1; void CreateBinTree(BTree &T); void preOrder(BTree T); void inOrder(BTree T); void postOrder(BTree T); int TreeNodes(BTree T); int LeafNodes(BTree T); int TreeNodedu(BTree T,char ch); void NodeLoc(BTree T,char c,int nodeloc); int Height(BTree T); BTree Parent(BTree T,char c); BTree NodeRC(BTree T,char c); BTree NodeLC(BTree T,char c); void CreateBinTree(BTree &T) {

      二叉树实验报告

      题目: 编程实现二叉查找树的建立、中序遍历、元素查找等功能,要求解释实现过程及演示实际例子的运行结果。 算法描述: 首先创建二叉树结点类,其主要包括:二叉树结点数据域,指向左、右子树的指针,构造函数,设置当前结点左、右子树、数据域以及判断当前结点是否为叶子结点等。然后进行二叉树类定义,其私有部分为定义二叉树根结点指针,公有部分主要包括:构造函数、析构函数、判断二叉树是否为空树、先,中,后序遍历的递归与非递归、二叉树删除、层序遍历以及二叉树搜索等。接下来将对一些重要函数算法进行描述: 1、isLeaf函数:若该结点的左子树和右子树都为空,则为叶子结点。 2、isEmpty函数:根结点为空则为空树。 3、Parent函数:首先判断给定结点是否有双亲,根结点和空结点一定无双亲,初始化一个临时变量,用于跟进查找双亲结点,查找到后其保存的便是双亲结点。先递归在左子树中查找,如果找到,便结束递归且返回双亲结点指针;如果没有找到,再递归在右子树中查找。如果都没有找到,说明给定结点的双亲结点不在该二叉树中。 4、LeftSibling(RightSibling)函数:首先找到当前结点的双亲,然后判断双亲结点左右子树是否为空,其中必然有一个不为空,返回另一个子树指针即可。 5、DeleteBinaryTree函数:首先判断是否为空树,若为空,则返回,然后递归删除左子树,递归删除右子树,最后删除根结点。 6、PreOrder函数:首先判断是否为空树,若为空,则返回,然后访问根结点,递归遍历左子树,递归遍历右子树,结束。 7、PreOrderWithoutRecusion函数:使用栈来模拟递归过程,首先申请栈,用于保存结点指针序列,申请指针pointer保存当前根指针,然后判断栈是否为空,若栈为空且pointer为空,跳出函数,否则若pointer不为空,访问pointer所指结点,pointer入栈,pointer指向其左子树;若pointer为空,弹出栈顶元素赋给pointer,pointer指向其右子树,结束。 8、CreateTree函数:采用先序遍历序列构造二叉树,设‘0’为空结点,输入非‘0’数,生成新结点,递归创建左子树和右子树。 9、Search函数:采用先序遍历查找给定元素是否在二叉树中,首先判断树是否是空树,若是空树,则返回空指针。然后初始化临时指针temp,查找成功后temp即为所给元素所在

      二叉树的存储与实现

      实验课程名称数据结构与算法 实验项目名称二叉树的存储与实现 年级 08 级 专业数学类 学生姓名 学号 理学院 实验时间:年月日

      学生实验室守则 一、按教学安排准时到实验室上实验课,不得迟到、早退和旷课。 二、进入实验室必须遵守实验室的各项规章制度,保持室内安静、整洁,不准在室内打闹、喧哗、吸烟、吃食物、随地吐痰、乱扔杂物,不准做与实验内容无关的事,非实验用品一律不准带进实验室。 三、实验前必须做好预习(或按要求写好预习报告),未做预习者不准参加实验。 四、实验必须服从教师的安排和指导,认真按规程操作,未经教师允许不得擅自动用仪器设备,特别是与本实验无关的仪器设备和设施,如擅自动用或违反操作规程造成损坏,应按规定赔偿,严重者给予纪律处分。 五、实验中要节约水、电、气及其它消耗材料。 六、细心观察、如实记录实验现象和结果,不得抄袭或随意更改原始记录和数据,不得擅离操作岗位和干扰他人实验。 七、使用易燃、易爆、腐蚀性、有毒有害物品或接触带电设备进行实验,应特别注意规范操作,注意防护;若发生意外,要保持冷静,并及时向指导教师和管理人员报告,不得自行处理。仪器设备发生故障和损坏,应立即停止实验,并主动向指导教师报告,不得自行拆卸查看和拼装。 八、实验完毕,应清理好实验仪器设备并放回原位,清扫好实验现场,经指导教师检查认可并将实验记录交指导教师检查签字后方可离去。 九、无故不参加实验者,应写出检查,提出申请并缴纳相应的实验费及材料消耗费,经批准后,方可补做。 十、自选实验,应事先预约,拟订出实验方案,经实验室主任同意后,在指导教师或实验技术人员的指导下进行。 十一、实验室内一切物品未经允许严禁带出室外,确需带出,必须经过批准并办理手续。 学生所在学院:理学院专业:数学类班级:08级

      数据结构实验报告之树与二叉树

      学生实验报告 学院:软通学院 课程名称:数据结构与算法 专业班级:软件142 班 姓名:邹洁蒙 学号: 0143990

      学生实验报告 (二) 一、实验综述 1、实验目的及要求 目的:1)掌握树与二叉树的基本概念; 2)掌握二叉树的顺序存储,二叉链表的先序遍历中序遍历和后序遍历算法; 3)掌握树的双亲表示法。 要求:1)编程:二叉树的顺序存储实现; 2)编程:二叉链表的先序遍历中序遍历和后序遍历实现; 3)编程:树的双亲表示法实现。 2、实验仪器、设备或软件 设备:PC 软件:VC6 二、实验过程(编程,调试,运行;请写上源码,要求要有注释) 1.编程:二叉树的顺序存储实现 代码: BiTree::BiTree()//建立存储空间 { data = new int[MAXSIZE]; count = 0; } void BiTree::AddNode(int e)//加结点 { int temp = 0; data[count] = e; count++;//从编号0开始保存 }

      运行截图: 2.编程:二叉链表的先序遍历中序遍历和后序遍历实现代码: void InOrderTraverse(BiTree* Head)//中序遍历 { if (Head) { InOrderTraverse(Head->LeftChild); cout << Head->data<<" "; InOrderTraverse(Head->RightChild); } } void PreOrderTraverse(BiTree* Head)//先序遍历 { if (Head) { cout << Head->data << " "; PreOrderTraverse(Head->LeftChild); PreOrderTraverse(Head->RightChild); } } void PostOrderTraverse(BiTree* Head)//后序遍历 { if (Head) { PostOrderTraverse(Head->LeftChild); PostOrderTraverse(Head->RightChild); cout << Head->data << " "; } } 运行截图:

      实验二叉树及其应用(严选材料)

      实验6:二叉树及其应用 一、实验目的 树是数据结构中应用极为广泛的非线性结构,本单元的实验达到熟悉二叉树的存储结构的特性,以及如何应用树结构解决具体问题。 二、问题描述 首先,掌握二叉树的各种存储结构和熟悉对二叉树的基本操作。其次,以二叉树表示算术表达式的基础上,设计一个十进制的四则运算的计算器。 如算术表达式:a+b*(c-d)-e/f 三、实验要求 1、 如果利用完全二叉树的性质和二叉链表结构建立一棵二叉树,分别计算 a) 统计叶子结点的个数。 b) 求二叉树的深度。 2、 十进制的四则运算的计算器可以接收用户来自键盘的输入。 3、 由输入的表达式字符串动态生成算术表达式所对应的二叉树。 4、 自动完成求值运算和输出结果。 四、实验环境 PC 微机 DOS 操作系统或 Windows 操作系统 Turbo C 程序集成环境或 Visual C++ 程序集成环境 五、实验步骤 1、根据二叉树的各种存储结构建立二叉树; 2、设计求叶子结点个数算法和树的深度算法; 3、根据表达式建立相应的二叉树,生成表达式树的模块; - + / a * b - e f C d

      4、根据表达式树,求出表达式值,生成求值模块; 5、程序运行效果,测试数据分析算法。 六、功能分析 存储结构 typedef union{ int Operator; // 操作符 float Operand; // 操作数 }Int_Float; //表达式树 typedef struct BinaryTreeNode{ Int_Float Data; //数据域 int IsOperator; //判断是不是操作数的标志位 struct BinaryTreeNode *RChild;//左子树 struct BinaryTreeNode *LChild;//右子树 }BiTreeNode, *lpBiTreeNode; //栈的定义 typedef struct { lpBiTreeNode *base; lpBiTreeNode *top; int stacksize; }SqStack; 函数一览表 lpBiTreeNode GetTop( SqStack s );//取栈顶结点函数 int IsEmpty( SqStack s );//判空函数 int InitStack( SqStack &s );//初始化栈函数 int Pop( SqStack &s, lpBiTreeNode &e );//出栈函数 int Push( SqStack &s, lpBiTreeNode e );//入栈函数 int In( int c, int* op );// 判断c是否在op中 int Precede( int theta1, int theta2 );//比较运算符号的优先级 int isNum( int c );//判断是不是数 int GetInput(Int_Float *Result);//读入输入的数 lpBiTreeNode CreateBiTree();//创建二叉树 bool calculate(lpBiTreeNode Root, float *result);//计算二叉树化表达式的值int getLeafNum(lpBiTreeNode Root);//计算二叉树的叶子结点数

      相关文档
      最新文档