数据结构(三)(笔记)

什么是树

客观世界中许多事物存在层次关系
人类社会家谱
社会组织结构
图书信息管理

分层次组织在管理上具有更高的效率!

数据管理的基本操作之一:查找

查找:根据某个给定关键字K,从集合R中找出关键字与K相同的记录

静态查找:集合中记录是固定的
没有插入和删除操作,只有查找
动态查找:集合中是动态变化的
除了查找,还可能发生插入和删除

静态查找

方法一:顺序查找

在这里插入图片描述
时间复杂度O(n)
哨兵
在查找方向的尽头设置哨兵元素,免去了查找过程中每次比较后都要判断查找位置是否越界的小技巧,看似与原先差别不大,但是总数据较多时,效率提高很明显,是非常好的编程技巧。当然,“哨兵”也不一定在数组开始,也可以再末尾”

方法二:二分查找

假设n个数据元素的关键字满足有序k1<k2<k3<…<kn
并且是连续存放(只能是数组),那么可以进行二分查找。

int BinarySearch( List Tbl,ElementType K)
{
	int left,right,mid,NoFound = -1;
	
	left = 1;
	right = Tbl->Length;
	while(left <= right)
	{
		mid = (left+right)/2;
		if(K<Tbl->Element[mid]) right = mid - 1;
		else if( K > Tbl->Element[mid]) left = mid + 1;
		else return mid;
	}
	return NotFound;
}

二分查找算法具有对数的时间复杂度O(logN)

在这里插入图片描述

树的定义

树(Tree):n个结点构成的有限集合。
当n等于0时,称为空树
对于任何一棵非空树,它具备以下性质:
树中有一个称为“根(Root)”的特殊节点,用r表示;
其余节点可分为m个互不相交的有限集T1,T2,…Tm,其中每个集合本身又是一棵树,称为原来树的“子树(SubTree)”
在这里插入图片描述
子树是不相交的;
除了根节点,每个结点有且仅有一个父节点;
一棵N个结点的树有N-1条边。
在这里插入图片描述
在这里插入图片描述

树的表示

儿子-兄弟表示法

每个指针有两个指针域,左边指向孩子结点,右边指向兄弟节点

二叉树的定义

在这里插入图片描述
在这里插入图片描述

二叉树几个重要性质

一个二叉树第i层的最大结点数为:2的i-1次方

深度为K的二叉树有最大结点总数为:2的k-1次方,看k>=1

对任何非空二叉树T,若n0表示叶节点的个数,n2是度为2的非叶节点的个数,那么两者满足关系n0=n2+1;

二叉树的抽象数据类型定义

类型名称:二叉树
数据对象集:一个有穷的结点集合。
若不为空,则由根节点和其左右二叉子树组成。
操作集:BT属于BinTree,Item属于ElementType,重要操作有:
1.Boolean IsEmpty(BinTree BT):判断BT是否为空;
2.void Traversal(BinTree BT):遍历,按某顺序访问每个结点;
3.BinTree CreatBinTree(): 创建一个二叉树。在这里插入图片描述

二叉树的存储结构

1.顺序存储结构
完全二叉树:
按从上到、从左到右顺序存储
n个结点的完全二叉树的结点父子关系:
非根节点的父节点的序号是i/2;
结点的左孩子结点的序号是2i;
结点的右孩子的序号是2i+1;

一般二叉树也可以采用这种结构,但会造成空间浪费…

2.链表存储

typedef struct TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode{
		ElementType Data;
		BinTree Left;
		BinTree Right;
}

二叉树的遍历

1.先序遍历
遍历过程:
访问根节点;
先序遍历其左子树;
先序遍历其右子树。

void PreOrderTraversal(BinTree BT)
{
		if(BT){
			printf("%d",BT->Data);
			PreOrderTraversal(BT->Left);
			PreOrderTraversal(BT->Right);
		}
}

2.中序遍历
遍历过程为:
中序遍历其左子树;
访问根节点;
中序遍历其右子树。

void InOrderTraversal(BinTree BT)
{
		if(BT){
				InOrderTraversal(BT->Left);
				printf("%d",BT->Data);
				InderTraversal(BT->Right);
		}
}

3.后序遍历
遍历过程为:
后序遍历其左子树;
后序遍历其右子树;
访问根节点。

void PostOrderTraversal(BinTree BT)
{
	if(BT)
	{
		PostOrderTraversal(BT->Left);
		PostOrderTraversal(BT->Right);
		printf("%d",BT->Data);
	}
}

二叉树的非递归遍历

中序遍历非递归遍历算法
非递归算法实现的基本思路:使用堆栈
遇到一个节点,就把它压栈,并去遍历她的左子树;
当左子树遍历结束后,从栈顶弹出这个结点并访问它;
然后按照其右指针再去中序遍历该结点的右子树。

void InOrderTraversal(BinTree BT)
{
	BinTree T=BT;
	Stack S = CreateStack(MaxSize);
	while(T||!IsEmpty(S)){
		Push(S,T);
		T = T->Left;
	}
	if(!IsEmpty(S)){
		T = Pop(S);
		printf("%5d",T->Data);
		T = T->Right;
	}
}

层序遍历

二叉树遍历的核心问题:二维结构的线性化
从结点访问其左右儿子结点
访问左儿子后,右儿子结点怎么办?
需要一个存储结构保存暂时不访问的结点
存储结构:堆栈,序列

队列实现:遍历从根节点开始,首先将根节点入队,然后开始执行循环:结点出队、访问该节点、其左右儿子入队

层序基本过程: 先根节点入队,然后:
1.从队列中取出一个元素;
2.访问该元素所指结点;
3.若该元素所指结点的左右孩子结点非空,则将其左右孩子的指针顺序入队。

void LevelOrderTraversal ( BinTree BT)
{
	Queue Q;
	BinTree T;
	if(!BT) return;  /*若是空树直接返回*/
	Q = CreatQueue(MaxSize); /*创建并初始化队列Q*/
	AddQ(Q,BT);
	while(!IsEmpty(Q))
	{
		T = DeleteQ(Q);
		printf("%d
",T->Data);
		if(T->Left) AddQ(Q,T->Left);
		if(T->Right) AddQ(Q,T->Right);
	}
}
	
原文地址:https://www.cnblogs.com/HBU-xuhaiyang/p/12520654.html