码迷,mamicode.com
首页 > 编程语言 > 详细

排序二叉树

时间:2016-01-07 01:10:00      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:请完成下面四个函数的定义(在tree.h文件中),使整个程序能够利用排序二叉树的结构对输入的数(不会出现相同的数),进行排序输出。节点的结构体在下面已给出,这个二叉树的特征是,左子数的值肯定比父节点小,右子树的值肯定比父节点的大。要求大家按照这个结构特征去构建二叉树,最后中序遍历输出就是我们要求的升序输出。

 

树的节点结构体为:

typedef struct Node {

         struct Node *left;

         struct Node *right;

         int value;

} Node;

 

中序遍历这个二叉树,按照升序输出,每个数之间有一个空格,最后一个数后也有一个空格。

void traverse_tree_inorder(Node *p);

 

回收建立二叉树时开辟的内存空间,提示类似后序遍历。

void recycle_nodes(Node *p);

 

将一个值为value的数插入到这个树中,但是要注意,需要插到那个地方,按照排序二叉树的要求来。

void insert_node(Node *p, int value);

 

初始化根节点的值。

Node* init_root(int value);

 

输入示例

5

23 3 53 333 2

 

输出示例

2 3 23 53 333  (最后一个数后有空格)

 

前置知识要求:数据结构二叉树,二叉树的中序遍历和后序遍历,递归函数设计,指针的使用,结构体。

知识介绍:

先序遍历:对一棵二叉树的前序遍历,先访问根结点,再访问左子树,然后访问右子树。

void preorder(Treenode *p) {

if (p!=NULL){

visit(p);

preorder(p->left);

preorder(p->right);

}

}

中序遍历:对一棵二叉树的中序遍历,先访问左子树,再访问根结点,然后访问右子树。

void inorder(Treenode *p) {

if (p!=NULL){

inorder(p->left);

visit(p);

inorder(p->right);

}

}

后序遍历:对一棵二叉树的后序遍历,先访问左子树,再访问右子树,然后访问根结点

void postorder(Treenode *p) {

if (p!=NULL){

postorder(p->left);

postorder(p->right);

visit(p);

}

}

 

 

 

 

一开始有点思路,但是不知道怎么打;后来打的过程中也出现了许多小问题,要注意,尤其出现了严重的内存泄漏;

1.#include<stdio.h>
2.#include<stdlib.h>
3.#include"tree.h"
4. 
5.int main(void) {
6.    int node_num, i = 0, temp;
7.    Node *root = NULL;
8.    scanf("%d", &node_num);
9.    while (i < node_num) {
10.        scanf("%d", &temp);
11.        if (i == 0) root = init_root(temp);
12.        else insert_node(root, temp);
13.        i++;
14.    }
15.    traverse_tree_inorder(root);
16.    printf("\n");
17.    recycle_nodes(root);
18.    return 0;
19.}

我的

 

#include<malloc.h> 

typedef struct Node {
    struct Node *left;
	struct Node *right;
	int value;
} Node;

Node* init_root(int value) {//初始化根节点的值。
	Node* rr;
	rr = malloc(sizeof(Node));
	rr->right = NULL;
    rr->left = NULL;
	rr->value = value;
	return rr;
}

void insert_node(Node *p, int value) {//将一个值为value的数插入到这个树中,但是要注意,需要插到那个地方,按照排序二叉树的要求来。
	Node* a = malloc(sizeof(Node));
    a->left = NULL;//这两行一开始我没有,出现了严重的内存泄漏,我还一直找不到哪里错了,以后一定要一动态申请就初始化NULL
    a->right = NULL;
	while (1) {
		if (value > p->value) {
			if (p->right == NULL) {
				p->right = a;
				a->value = value;
				break;
			} else {
				p = p->right;
			}
		}
		if (value < p->value) {
			if (p->left == NULL) {
				p->left = a;
				a->value = value;
				break;
			} else {
				p = p->left;
			}
		}
	}
	return;
}

void traverse_tree_inorder(Node *p) {//中序遍历这个二叉树,按照升序输出,每个数之间有一个空格,最后一个数后也有一个空格	if (p != NULL) {
		traverse_tree_inorder(p->left);
		printf("%d ", p->value);
		traverse_tree_inorder(p->right);
	}
}

void recycle_nodes(Node *p) {//。回收建立二叉树时开辟的内存空间,提示类似后序遍历

	if (p != NULL) {
		recycle_nodes(p->left);
		recycle_nodes(p->right);
	    free(p);
	}
}

 

  

 

①内存泄漏主要有以下几种情况:

  • 内存分配未成功,却使用了它。
  • 内存分配虽然成功,但是尚未初始化就引用它。-----这题就是因为未初始化一个指针卡壳了好久,所以,以后一有动态内存申请就进行初始化=NULL;其次记得释放申请过的内存
  • 内存分配成功并且已经初始化,但操作越过了内存的边界。
  • 忘记了释放内存,造成内存泄露。----这也是常犯的错误
  • 释放了内存却继续使用它
  • 对动态内存的错误观念:有人对某一只在函数内使用的指针动态分配了内存,用完后不释放。其理由是:函数运行结束后,函数内的所有变量全部消亡。这是错误的。动态分配的内存是在“堆”里定义,并不随函数结束而消亡。

    有人对某动态分配了内存的指针,用完后直接设置为NULL。其理由是:已经为NULL了,这就释放了。这也是错误的。指针可以任意赋值,而内存并没有释放;相反,内存释放后,指针也并不为NULL。

 

②malloc()和free(),都是标准函数,在stdlib.h中定义。

malloc()我一般在<malloc.h>里面定义

③原来我一直纠结,我把main里的root指针,传进去命名为p,那我对p指向的地址改变,那么root会不会变,结果是当然不会变啦,因为返回值是void,所以原来main里root指向的初始位置

④那个while和break用的也很巧妙,一般我也很少用while(1),但是这道题需要一直遍历直到出现NULL

 

排序二叉树

标签:

原文地址:http://www.cnblogs.com/-lyric/p/5107876.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!