(郝斌讲学)数据结构学习篇(七)---树

树定义

       专业定义:有且只有一个称为根的节点,有若干个互不相交的子树,这些子树的本身也是一棵树。

       通俗的定义:树是由节点和边组成;每个节点只有一个父节点但可以有多个子节点;但有一个节点例外,该节点没有父节点,此节点称为根节点。

 

专业术语

       节点 父节点 子节点 子孙 堂兄弟 深度

深度:从根节点到底层节点的层数称之为深度。根节点是第一层.

叶子节点:没有子节点的节点.

非终端节点:实际上就是非叶子节点.

度:子节点的个数称之为度.

 

树的分类

       一般树:任意一个节点的子节点的个数都不受限制.

       二叉树:任意一个节点的子节点的个数最多2个,且子节点的位置不可更改。

       二叉树是有序树。

森林:n个互不相交的树的集合.

 

二叉树的分类

       一般二叉树

       满二叉树:在不增加树的层数的前提下,无法再多添加一个节点的二叉树就是满二叉树.

       完全二叉树:如果只是删除满二叉树最底层、最右边的连续若干个节点,这样形成的二叉树就是完全二叉树.

       满二叉树是完全二叉树的一个特例.

 

树的存储

       二叉树的存储

              连续存储【完全二叉树】

                     优点:查找某个节点的父节点和子节点

                     缺点:耗用内存空间过大.

       一般树的存储

              双亲表示法

                     求父节点方便----求下标,从0开始

              孩子表示法

              求子节点方便

       双亲孩子表示法

              求父节点和子节点都很方便

二叉树的表示法

       把一个普通树转化程二叉树来存储.

具体转化方法:

       设法保证任意一个节点的左指针域指向它的第一个孩子,

       右指针域指向它的下一个兄弟.

只要能满足此条件,就可以把一个普通树转化为二叉树.

一个普通树转化为的二叉树,一定是没有右子树的。

森林的存储:

       先把森林转化为二叉树,再存储二叉树.

#include <stdio.h>
#include <malloc.h>

/**
  *静态构建一个二叉树
  *2014/8/30
  */
struct BTNode * CreateBTree(void);
void PreTraverseBTree(struct BTNode * pT);
void InTraverseBTree(struct BTNode * pT);
void PostTraverseBTree(struct BTNode * pT);

typedef struct BTNode
{
	int data;
	struct BTNode * pLchild; //p是指针, L是左, child是孩子
	struct BTNode * pRchild;
};

int main(void)
{
	struct BTNode * pT = CreateBTree();
//	PreTraverseBTree(pT);
//	InTraverseBTree(pT);
	PostTraverseBTree(pT);

	return 0;
}

//后序遍历
void PostTraverseBTree(struct BTNode * pT)
{
	if(NULL != pT)
	{
		if(NULL != pT->pLchild)
		{
			PreTraverseBTree(pT->pLchild);
		}

		if(NULL != pT->pRchild)
		{
			PreTraverseBTree(pT->pRchild);
		}

		printf("%c\n", pT->data);  //输出跟元素

	}

}

//中序遍历
void InTraverseBTree(struct BTNode * pT)
{
	if(NULL != pT)
	{
		if(NULL != pT->pLchild)
		{
			PreTraverseBTree(pT->pLchild);
		}

		printf("%c\n", pT->data);  //输出跟元素

		if(NULL != pT->pRchild)
		{
			PreTraverseBTree(pT->pRchild);
		}

	}

}

//先序遍历
void PreTraverseBTree(struct BTNode * pT)
{
	if(pT != NULL)
	{
		printf("%c\n", pT->data);  //输出跟元素

		if(NULL != pT->pLchild)
		{
			PreTraverseBTree(pT->pLchild);
		}

		if(NULL != pT->pRchild)
		{
			PreTraverseBTree(pT->pRchild);
		}
		// pT->pLchild  可以代表整个左子树
	}
	/**
		伪算法
		先访问根节点;
		再先序遍历左子树;
		再先序遍历右子树.
	*/
}

//静态创建二叉树
struct BTNode * CreateBTree(void)
{
	struct BTNode * pA = (struct BTNode*)malloc(sizeof(struct BTNode));
	struct BTNode * pB = (struct BTNode*)malloc(sizeof(struct BTNode));
	struct BTNode * pC = (struct BTNode*)malloc(sizeof(struct BTNode));
	struct BTNode * pD = (struct BTNode*)malloc(sizeof(struct BTNode));
	struct BTNode * pE = (struct BTNode*)malloc(sizeof(struct BTNode));

	pA->data = 'A';
	pB->data = 'B';
	pC->data = 'C';
	pD->data = 'D';
	pE->data = 'E';

	pA->pLchild = pB;
	pA->pRchild = pC;

	pB->pLchild = pB->pRchild = NULL;

	pC->pLchild = pD;
	pC->pRchild = NULL;

	pD->pLchild = NULL;
	pD->pRchild = pE;

	pE->pLchild = pE->pRchild = NULL;

	return pA;  //根节点的地址

}

树的应用

树是数据库中数据组织一种重要形式。

操作系统子父进程的关系本身就是一棵树

面向对象语言中类的继承关系。

哈夫曼树。

 

排序和查找的关系

       排序是查找的前提。

       排序是重点。

/**
  *快速排序
  *
  */
#include <stdio.h>

int FindPos(int *a, int low, int high);
void QuickSort(int *a, int low, int high);

int main(void)
{
	int a[6] = {2, 1, 0, 5, 4, 3};
	int i;

	//第二个参数代表第一个元素的下标
	//第三个参数代表最后一个元素的下标
	QuickSort(a, 0, 5);

	for(i=0; i<6; ++i)
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	return 0;
}

void QuickSort(int *a, int low, int high)
{
	int pos;

	if(low < high)
	{
		pos = FindPos(a, low, high);
		QuickSort(a, low, pos-1);  //左边的一半
		QuickSort(a, pos+1, high); //右边的一半
	}
}

int FindPos(int *a, int low, int high)
{
	int val = a[low];

	while(low < high)
	{
		while(low < high && a[high] >= val)
		{
			--high;
		}
		a[low] = a[high];

		while(low < high && a[low] <= val)
		{
			++low;
		}
		a[low] = val;

	} //终止while循环之后, low和high一定是相等的

	return high;

}

时间: 2024-10-23 11:01:53

(郝斌讲学)数据结构学习篇(七)---树的相关文章

(郝斌讲学)数据结构学习篇(五)---队列的CRUD操作

队列 什么是队列? 一种可以实现"先进先出"的存储结构. 出队  入队  -->>队列 出栈  压栈  -->>栈 链式队列 ---用链表实现的 静态队列 ---用数组实现的 静态队列通常必须是循环队列.. 039.循环队列需要几个参数来确定极其含义的讲解 front代表的是队列的第一个元素 rear代表的是队列的最后一个有效元素的下一个元素 队列为空: front和rear的值相等,但不一定为零 队列初始化 front和rear的值都是零. 循环队列入队的伪算

(郝斌讲学)数据结构学习篇(四)---栈的CRUD操作

栈 栈类似于箱子. 静态栈.动态栈. 关于栈的操作 #include<stdio.h> #include<malloc.h> #include<stdlib.h> typedef struct Node { int data; struct Node *pNext; }NODE, *PNODE; typedef struct Stack { PNODE pTop; PNODE pBottom; }STACK, *PSTACK; void init(PSTACK); vo

(郝斌讲学)数据结构学习篇(三)---链表的CRUD操作

024.链表的创建和链表遍历的算法演示 <span style="font-size:14px;">#include <stdio.h> #include <malloc.h> #include <stdlib.h> typedef struct Node { int data; struct Node *pNext; }NODE, *PNODE; //NODE 等价于struct Node, PNODE 等价于struct Node *

【数据结构学习】字典树Trie

#1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一本词典,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能对于每一个我给出的字符串,都在这个词典里面找到以这个字符串开头的所有单词呢?” 身经百战的小Ho答道:“怎么会不能呢!你每给我一个字符串,我就依次遍历词典里的所有单词,检查你给我的字

数据结构学习笔记(树、二叉树)

树(一对多的数据结构) 树(Tree)是n(n>=0)个结点的有限集.n=0时称为空树.在任意一颗非空树种: (1)有且仅有一个特定的称为根(Root)的结点: (2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1.T2........Tn,其中每一个集合本身又是一棵树,并且称为根的子树. 对于树的定义还需要强调两点:1.n>0时根结点是唯一的,不可能存在多个根结点,数据结构中的树只能有一个根结点.2.m>0时,子树的个数没有限制,但它们一定是互不相交的. 结点

数据结构学习笔记04树(二叉树、二叉搜索树、平衡二叉树)

一.树 树的基本术语 ①结点的度(Degree):结点的子树个数 ②树的度:树的所有结点中最大的度数 ③叶结点(Leaf):度为0的结点 ④父结点(Parent):有子树的结点是其子树的根结点的父结点 ⑤子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点:子结点也称孩子结点. ⑥兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点. ⑦路径和路径长度:从结点n1到nk的路径为一个结点序列n1 , n2 ,… , nk , ni是 ni+1的父结点.路径所包含边

数据结构学习笔记04树(堆 哈夫曼树 并查集)

一.堆(heap) 优先队列(Priority Queue):特殊的“队列”,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序. 数组 : 插入 — 元素总是插入尾部 ~ O ( 1 ) 删除 — 查找最大(或最小)关键字 ~ O ( n ) 从数组中删去需要移动元素 ~ O( n ) 链表: 插入 — 元素总是插入链表的头部 ~ O ( 1 ) 删除 — 查找最大(或最小)关键字 ~ O ( n ) 删去结点 ~ O( 1 ) 有序数组: 插入 — 找到合适的位置

邓俊辉数据结构学习-8-1-伸展树

高级搜索树--伸展树 对于维护平衡因子,感觉很麻烦,希望抛弃掉平衡因子,使用更加潇洒的模式. 要求: 对于伸展树来说,也不做过多掌握 主要明白利用数据的局部性,我们可以实施的新策略 概述 背景知识补充: 数据局部性 刚被访问过得数据很快会被再次访问 因此这一次访问过的节点,极有可能再次被访问, 能够实现这种特性的树就是伸展树--就像自适应链表一样 新的名词: 自适应链表 在某一段时间内,将经常需要访问的元素尽可能的放到链表前面 大概实现:就是将上次访问过的节点移动到链表的前端 电脑缓存会充分利用

[数据结构学习]分块与树状数组

分块与树状数组均在区间问题上有重要的应用 emm分块效率上不如树状数组,但是思路比较好想 先说分块: 将n个数的序列分为sqrt(n)块,预处理每块数据的信息以加快后续对区间信息的查询 先上一段代码: const int maxn = 5e5 + 50; int sum[maxn],a[maxn],l[maxn],r[maxn],belong[maxn]; int block,num; void build(){ block = sqrt(n); num = n/block; if(n%bloc