1、树

1、1树的概念

		树是由一个或者一个以上的结点组成,存在一个特殊的节点,称为树根,每个结点由数据和指针构成。
		当节点数量为0时,称为空树。

1、2树的专有名词介绍

结点的度(degree):每个结点所有字数的个数。

树的度:树的所有结点中最大的度数。

结点层数:规定在根结点在1层,其它任一结点的层数是其父结点的层数加1 。

叶节点:度为0的结点。

兄弟结点:具有同一个父结点的各个结点彼此是兄弟结点。

路径和路径长度:从结点n1到 到nk的路径为一个结点序列n1 , n2 ,… , nk , ni是ni+1的父结点。路径所包含边的个数为路径的长度。

结点的层次:根节点的层数为1,其他结点的层数为父结点层数+1.

树的深度:树中所有结点的最大层次是树的深度。

2、二叉树及其存储结构

2.1二叉树的定义

一个又穷的结点的集合,可以为空,若不为空,则它由根节点和成为其左子树和右子树的两个不相交的二叉树组成。

2.2特殊的二叉树

斜二叉树、完美二叉树、完全二叉树

2.3二叉树的性质

1.二叉树的第i层的最大节点数为2^(i-1).i>=1

2.深度为k的二叉树最多有2^k-1个结点

3.对于任何非空二叉树,n0=n2+1(n0为度为0的结点,n2为度为2的结点).

2.4二叉树的存储结构

1.顺序存储:按照从上到下、从左到右的顺序存储(完全二叉树)

2.链表存储

struct TreeNode
{
	ElementType Data;
	TreeNode* Lchild;
	TreeNode* Rchild;
};

3、二叉树的遍历

3.1递归遍历

3.1.1先序遍历

根节点->左子树->右子树

void Traverse(TreeNode* T)
{
	if (T)
	{
		dosomething();
		Traverse(T->Lchild);
		Traverse(T->Rchild);
	}
}

3.1.2中序遍历

左子树->根节点->右子树

void Traverse(TreeNode* T)
{
	if (T)
	{
		Traverse(T->Lchild);
		dosomething();
		Traverse(T->Rchild);
	}
}

3.1.3后序遍历

左子树->右子树->根节点

void Traverse(TreeNode* T)
{
	if (T)
	{
		Traverse(T->Lchild);
		Traverse(T->Rchild);
		dosomething();
	}
}

3.2非递归遍历

3.2.1非递归先序遍历

//非递归实现先序遍历
void PreTraverse(TreeNode* T)
{
	if (!T)
		return;
	Stack<TreeNode*> s;
	while (!s.IsEmpty()||T)
	{
		while(T)
		{
			s.Push(T);
			visit(T);
			T = T->Lchild;
		}
		if(!s.IsEmpty())
		{
			T = s.GetTop();
			s.Pop();
			T = T->Rchild;
		}
	}
}

3.2.2非递归中序遍历

//非递归实现中序遍历
void MidTraverse(TreeNode* T)
{
	if (!T)
		return;
	Stack<TreeNode*> s;
	
	while (!s.IsEmpty()||T)
	{
		while (T)
		{
			s.Push(T);
			T = T->Lchild;
		}
		if (!s.IsEmpty())
		{
			T = s.GetTop();
			visit(T);
			s.Pop();
			T = T->Rchild;
		}
	}
}

3.2.3非递归后序遍历

//非递归实现后序遍历
//后序遍历的顺序为(左->右->根),根据(根->右->左)的顺序遍历,在将结果逆序输出即是后序遍历了
void LastTraverse(TreeNode* T)
{
	if (!T)
		return;
	Stack<TreeNode*> s;
	Stack<TreeNode*> v;
	
	while (!s.IsEmpty()||T)
	{
		while (T)
		{
			s.Push(T);
			v.Push(T);
			T = T->Rchild;
		}
		if (!s.IsEmpty())
		{
			T = s.GetTop();
			s.Pop();
			T = T->Lchild;
		}
	}
	while (!v.IsEmpty())
	{
		T = v.GetTop();
		visit(T);
		v.Pop();
	}
}

3.2.4非递归层序遍历

//非递归实现层序遍历
void LevelTraverse(TreeNode* T)
{
	if (!T)
		return;
	Queue<TreeNode*> q;
	q.En_Queue(T);
	while (!q.IsEmpty())
	{
		T = q.De_Queue();
		visit(T);
		if (T->Lchild)
			q.En_Queue(T->Lchild);
		if (T->Rchild)
			q.En_Queue(T->Rchild);
	}
}

4、二叉搜索树

4.1什么是二叉搜索树

二叉搜索树又称二叉排序树、二叉查找树

若二叉排序树非空,则满足以下条件
1.非空左子树的所有键值小于其根结点
2.非空右子树的所有键值大于其根结点
3.左右子树都是二叉搜索树

4.2二叉树的操作集

4.2.1创建树节点

//创建结点
TreeNode* CreatNode(ElementType X)
{
	TreeNode* T = new TreeNode;
	T->Data = X;
	T->Lchild = NULL;
	T->Rchild = NULL;
}

4.2.2插入

//插入元素X到二叉树,返回根节点,如果二叉树中已有改元素,则插入失败,返回空指针
TreeNode* Insert(TreeNode* T,ElementType X)
{
	if (!T)
		T = CreatNode(X);
	else if (X < T->Data)
		T->Lchild = Insert(T->Lchild, X);
	else if (X > T->Data)
		T->Rchild = Insert(T->Rchild, X);
	else
		T = NULL;
	return T;
}

4.2.3删除

//删除元素X
TreeNode* Delete(TreeNode* T,ElementType X)
{
	TreeNode* temp = NULL;
	if (!T)
		return NULL;
	if (X < T->Data)
		T->Lchild = Delete(T->Lchild, X);
	else if(X>T->Data)
		T->Rchild = Delete(T->Rchild, X);
	else
	{
		if (T->Lchild && T->Rchild)
		{
			temp = FindMin(T->Rchild);
			T->Data = temp->Data;
			T->Rchild=Delete(T->Rchild, T->Data);
		}
		else
		{
			temp = T;
			if (!T->Lchild)
				T = T->Rchild;
			else if (!T->Rchild)
				T = T->Lchild;
			delete temp;
		}
	}
	return T;
}

4.2.4查找

4.2.4.1查找元素X

//查找元素X,不存在返回NULL
TreeNode* Find(TreeNode* T,ElementType X)
{
	if (!T)
		return NULL;
	else if (X < T->Data)
		return Find(T->Lchild, X);
	else if (X > T->Data)
		return Find(T->Rchild, X);
	else
		return T;
}

4.2.4.2查找最大的元素

//查找二叉树中最大的元素
TreeNode* FindMax(TreeNode* T)
{
	if (!T)
		return NULL;
	if (T->Rchild)
		return FindMax(T->Rchild);
	else
		return T;
}

4.2.4.3查找最小的元素

//查找二叉树中最小的元素
TreeNode* FindMin(TreeNode* T)
{
	if (!T)
		return NULL;
	if (T->Lchild)
		return FindMin(T->Lchild);
	else
		return T;
}

5、二叉平衡树(AVL树)

5.1什么是二叉平衡树

1.平衡因子(BF)=hL-hR
2.平衡二叉树的任意节点的平衡因子的绝对值不超过1,即 | BF |<=1

5.2平衡二叉树的调整

5.2.1插入

TreeNode_AVL* Insert_AVL(TreeNode_AVL* T,ElementType X)
{
	if (!T)
	{
		T = CreatNode(X);
	}
	else if (X < T->Data)
	{
		T->Lchild = Insert_AVL(T->Lchild, X);
		if (Geth(T->Lchild) - Geth(T->Rchild) == 2)
			if (T->Lchild->Data > X)
				T = LL(T);
			else
				T = LR(T);
	}
	else if (X > T->Data)
	{
		T->Rchild = Insert_AVL(T->Rchild, X);
		if (Geth(T->Lchild) - Geth(T->Rchild) == -2)
			if (T->Rchild->Data > X)
				T = RL(T);
			else
				T = RR(T);
	}
	T->height = Max(Geth(T->Lchild),Geth(T->Rchild)) + 1;
	return T;
}

5.2.2 RR旋转

TreeNode_AVL* RR(TreeNode_AVL* A)
{
	TreeNode_AVL* B = A->Rchild;
	A->Rchild = B->Lchild;
	B->Lchild = A;
	A->height = Max(Geth(A->Lchild), Geth(A->Rchild)) + 1;
	B->height = Max(Geth(B->Lchild), Geth(B->Rchild)) + 1;
	
	return B;
}

5.2.3 LL旋转

TreeNode_AVL* LL(TreeNode_AVL* A)
{
	TreeNode_AVL* B = A->Lchild;
	A->Lchild = B->Rchild;
	B->Rchild = A;
	A->height = Max(Geth(A->Lchild), Geth(A->Rchild)) + 1;
	B->height = Max(Geth(B->Lchild), Geth(B->Rchild)) + 1;
	return B;
}

5.2.4 RL旋转

TreeNode_AVL* RL(TreeNode_AVL* A)
{
	TreeNode_AVL* B = A->Rchild;
	TreeNode_AVL* C = A->Rchild->Lchild;
	A->Rchild = C->Lchild;
	B->Lchild = C->Rchild;
	C->Rchild = B;
	C->Lchild = A;
	A->height = Max(Geth(A->Lchild), Geth(A->Rchild)) + 1;
	B->height = Max(Geth(B->Lchild), Geth(B->Rchild)) + 1;
	C->height = Max(Geth(C->Lchild), Geth(C->Rchild)) + 1;
	return C;
}

5.2.5 LR旋转

TreeNode_AVL* LR(TreeNode_AVL* A)
{
	TreeNode_AVL* B = A->Lchild;
	TreeNode_AVL* C = A->Lchild->Rchild;
	A->Lchild = C->Rchild;
	B->Rchild = C->Lchild;
	C->Lchild = B;
	C->Rchild = A;
	A->height = Max(Geth(A->Lchild), Geth(A->Rchild)) + 1;
	B->height = Max(Geth(B->Lchild), Geth(B->Rchild)) + 1;
	C->height = Max(Geth(C->Lchild), Geth(C->Rchild)) + 1;
	return C;
}

6、堆

6.1什么是堆

优先队列(Priority Queue):特殊的“ 队列”,取出元素的顺序是依照元素的优先权(关键字)。

大顶堆(最大堆):堆顶元素是最大值;

小顶堆(最小堆):堆顶元素是最小值;

从根节点到任意节点的路径上的值是有序的

6.2堆的创建

1.采用数组的方式
1)普通数组
插入:元素插入到数组尾部 ~O(1)
删除:查找最大(小)的元素—>删除–>后面的元素向前移动 ~O(n)+O(n)
2)有序数组
插入:找位置–>移动元素–>插入 ~ O(n)或O(log2n)+O((n)+O(1)
删除:删除最后一个 ~O(1)
2.采用链表的方式
1)普通链表
插入:插入链表头 ~O(1)
删除:查找最大(小)值–>删除 ~O(n)+O(1)
2)有序链表
插入:查找位置值–>插入节点 ~O(n)+O(1)
删除:删除链表头 ~O(1)

6.3二叉树堆

1)用完全二叉树的方式存储到数组中
图片
2)特征:
满足以下条件的才能称为堆
~任意节点到根节点都满足有序性,即该序列递增或递减
~二叉树是完全二叉树
~任意节点大于其左右子树的所有结点(若其不为空)

6.4堆的操作集(二叉树)

6.4.1最大堆创建

typedef struct Heap Heap;
struct Heap
{
	Elementtype* Element;
	int size;
	int capacity;
};

Heap* CreatHeap()
{
	Heap* heap = new Heap;
	heap->capacity = CAPACITY;
	heap->size = 0;
	heap->Element = new Elementtype[heap->capacity];
	heap->Element[0] = MAXDATA;
	return heap;
}

6.4.2最大堆插入

bool IsFull(Heap* heap)
{
	if (heap->size < (heap->capacity) - 1)
		return false;
	else
		return true;
}
void InsertHeap(Elementtype x,Heap* heap)
{
	if (IsFull(heap))
		return;
	int i = ++heap->size;
	for (; heap->Element[i / 2] < x; i /= 2)
		heap->Element[i] = heap->Element[i / 2];
	heap->Element[i] = x;
}

6.4.3最大堆删除


bool IsEmpty(Heap* heap)
{
	if (heap->size <= 0)
		return true;
	else
		return true;
}
Elementtype Delete(Heap* heap)
{
	if (IsEmpty(heap))
		throw "最大堆空,不能删除";
	Elementtype x = heap->Element[1], temp = heap->Element[heap->size--];
	int parent, child;
	for (parent=1;parent*2<=heap->size; parent = child)
	{
		child = parent * 2;
		if ((parent * 2) != heap->size && heap->Element[child] < heap->Element[child + 1])
			child++;
		if (temp > heap->Element[child])
			break;
		else
			heap->Element[parent] = heap->Element[child];
	}
	heap->Element[parent] = temp;
	return x;
}

6.4.4已有元素下生成最大堆的方法

  1. 将元素一个一个插入最大堆 ~O(N log N)

  2. 先将元素放入完全二叉树(数组)中,在调整使其成为最大堆 ~O(N)

思路:从序号最小的根节点开始,使其成为一个最大堆,再调整前一个,使其成为最大堆,一直调整到根节点,这时整棵树成为最小堆。

7、哈夫曼树(最优二叉树)与哈夫曼编码

7.1什么是哈夫曼树

  1. 带权路径长度(WPL):设二叉树有n个叶子结点。每个叶子节点带有权值wk,从根节点到叶子结点的长度为lk,则每个叶子节点的带权路径长度之和就是:WPL= ∑ i = 1 n \sum_{i=1}^n i=1nwk * lk
  2. 哈夫曼树(最优二叉树):WPL最小的树

7.2哈夫曼树的构造

思路:所有结点建立一个集合,{ 从集合中取两个权重最小的根节点node1、node2,创建一个新节点node3,权重等于node1、node2权重之和,将node1和node2连接到node3上,将node3放入节点集合结点,} 重复花括号中的过程直到节点集合中只有一个根节点,这个节点就是哈夫曼树的根节点

HuffmanTree* CreatHuffmanTree();
typedef struct TreeNode* HuffmanTree;
struct TreeNode {
	int Weight;
	HuffmanTree Left, Right;
}
HuffmanTree Huffman(MinHeap H)
{ /* 假设H->Size 个权值已经存在H->Elements[]->Weight 里 */
	int i; HuffmanTree T;
	BuildMinHeap(H); /* 将H->Elements[] 按权值调整为最小堆*/
	for (i = 1; i < H->Size; i++) { /* 做H->Size-1 次合并*/
		T = malloc(sizeof(struct TreeNode)); /* 建立新结点*/
		T->Left = DeleteMin(H);
		/* 从最小堆中删除一个结点 , 作为新T 的左子结点*/
		T->Right = DeleteMin(H);
		/* 从最小堆中删除一个结点 , 作为新T 的右子结点*/
		T->Weight = T->Left->Weight + T->Right->Weight;
		/* 计算新权值*/
		Insert(H, T); /* 将新T 插入最小堆*/
	}
	T = DeleteMin(H);
	return T;
}

7.3哈夫曼编码

  1. 创建结点,结点权重就是该符号的出现频率,节点包含该字符,非叶子节点字符值为空
  2. 建立哈夫曼树
  3. 设左子树为0,右子树为1,从根节点到叶子结点的路径就是该叶子结点字符的编码(字符只会出现在叶子结点)

7.4前缀码

  1. 前缀码prefix code:任何字符的编码都不是另一字符编码的前缀(可以无二义地解码)
  2. 哈夫曼编码就是一种前缀码

8、集合及运算

8.1集合的表示(数组)

思路:创建一个一维结构体数组,结构体中包含Data(数据)和Parent(集合第一个元素的数组下标),若其自身就是第一个元素,则为-1;
在这里插入图片描述

8.2集合运算

8.2.1查找元素所在的集合

#define MaxSize 100 //数组的容量
#define ElementType int //数据类型
typedef struct Node NOde;
struct Node
{
	ElementType Data;
	int Parent;
}
int Find( Node S[ ], ElementType X )
{ 
int i;
for ( i=0; i < MaxSize && S[i].Data != X; i++) ; //找元素
if( i >= MaxSize ) 
	return -1;
for( ; S[i].Parent >= 0; i = S[i].Parent ) ; //找爹
return i; 
}

8.2.2集合的并运算

void Union( Node S[ ], ElementType X1, ElementType X2 )
{
int Root1, Root2;
Root1 = Find(S, X1);
Root2 = Find(S, X2);
if ( Root1 != Root2 )S[Root2].Parent = Root1;
}

9、红黑树

建议去看看这个大神写的:https://www.zhihu.com/question/312327402/answer/1560653215
ps:写的非常详细,建议耐心看完,你会有不一样的理解,深入浅

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值