文章目录
前言
一、树的概念及其结构
1.树的概念
树中有一个特殊的节点,称为根节点,根节点没有前驱节点。除根节点之外,其余节点被分成M(M>0)个互不相交的集合,其中每一个集合又是一课结构与树类似的子树。每科子树的根节点有且只有一个前驱,可以有0个或多个后继结点,因此,树是递归定义的。
图示:
注意:1.树形结构中,子树之间不能有交集,否则就不是树形结构。
2.除了根节点外,每个节点有且仅有一个父节点。
3.一棵N个节点的树有N-1条边。
2.树的相关概念
图示
树的表示
由于树的结构比较麻烦,既要保存他的值也要保存节点与节点之间的关系,在实际问题中表示树的方法很多,如双亲表示法、孩子表示法、孩子双亲表示法以及孩子兄弟表示法等。
以下用孩子兄弟法来表示树
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BinaryTreeNode *firstchild;//第一个孩子节点
BinaryTreeNode *pNextbrother;//其兄弟节点
BTDataType data;//节点的数据域
} BTNode;
二、二叉树概念及其结构
1.二叉树的概念
二叉树:由一个根节点加上两棵别称为左子树和右子树的二叉树组成(或者为空)。
注意:1.二叉树不存在度大于2的节点。
2.二叉树有左右之分,次序不能颠倒,因此二叉树是有序树。
任意的二叉树都是由以下情况中复合而成的(空树、只有根节点、只有左子树、只有右子树、左右字数均存在)
2.满二叉树和完全二叉树
满二叉树:一个二叉树,如果每层的结点数都达到了最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且节点的总数是2^k -1,则就是满二叉树。
完全二叉树:完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个节点都与深度为K的满二叉树中编号从1至n的结点一一对应时称为完全二叉树。要注意的是满二叉树是一种特殊的完全二叉树(判断:前N-1层满)。
图示:
3.二叉树的性质
1.若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点。
2.若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h-1.
3.对于任何一棵二叉树,如果度为0其叶子结点个数为n0,度为2的分支结点个数为n2,则有n0=n2+1。
4.若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1).
5.对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的节点有:
若i>0,i位置节点的双亲序号:(i-1)/2;
若2*i+1<n,左孩子序号:2*i+1,2*i+1>=n否则无左孩子。
若2*i+2<n,右孩子序号:2*i+2,2*i+2>=n否则无右孩子。
二叉树的存储结构
二叉树一般可以使用两种结构存储,一种是顺序存储,另一种是链式存储。
1.顺序存储
顺序结构存储使用数组进行存储数据,一般适用于完全二叉树,避免空间的浪费。(二叉树顺序存储在物理上是一个数组,在逻辑上是一棵二叉树。)。
下标计算父子间的关系
leftchild=parent*2+1;
rightchild=parent*2+2;
parent=(child-1)/2;
2.链式存储
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链表来只是元素的逻辑关系,通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该节点左孩子和右孩子所在的链节点的存储地址,链式结构又分为二叉链和三叉链。
二叉树的顺序结构及实现
1.二叉树的顺序结构
由于普通二叉树是不适合用数组来存储的,可能存在大量的空间浪费,而完全二叉树更适合使用顺序表结构存储。实际上我们把堆使用顺序结构中的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间的堆是两回事,一个是数据结构,一个是操作系统中给管理内存的一块区域分段。
2.堆的概念及其结构
将一个集合内的所有元素按完全二叉树的顺序存储在一个一维数组中,并满足树中的父亲都是大于等于孩子或者是小于等于孩子,前者成为大根堆,后者称为小根堆。
图示:
3.堆的实现
1.堆的创建
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a;
int size;
int capacity;
}Hp;
2.堆的初始化
void HeapInit(HP* PHP)
{
assert(PHP);
PHP->a = nullptr;
PHP->size = PHP->capacity = 0;
}
3.堆的销毁
void HeapDestroy(HP* PHP)
{
assert(PHP);
delete PHP->a;
PHP->a = nullptr;
PHP->capacity = PHP->size = 0;
}
4.堆的向上调整
void AdjustUp(HPDataType*a,int child)
{
int parent= (child - 1) / 2;
while (child > 0)//while(parent>=0)不适合因为parent=0时会进入死循环
{
if (a[child] < a[parent])
{
swap(a[child],a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
5.堆的插入
void HeapPush(HP* PHP, HPDataType x)
{
assert(PHP);
if (PHP->size == PHP->capacity)
{
int newcapacity = PHP->capacity == 0 ? 4 : PHP->capacity * 2;
HPDataType*tmp = (HPDataType*)realloc(PHP->a, newcapacity);
if (tmp == nullptr)
perror("realloc fail!");
}
PHP->a[PHP->size] = x;
PHP->size++;
AdjustUp(PHP->a, PHP->size-1);
}
6.堆的向下调整
void AdjustDown(HPDataType* a, int size, int parent)
{
int child = parent * 2 + 1;
while (child< size)
{
if (child + 1 < size && a[child+1] < a[child])//防止越界
child++;
if (a[child] < a[parent])
{
swap(a[child], a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
7.堆的删除
void HeapPop(HP* PHP)
{
assert(PHP);
assert(PHP->size);
swap(PHP->a[0], PHP->a[PHP->size - 1]);
PHP->size--;
AdjustDown(PHP->a, PHP->size, 0);
}
8.堆顶数据
HPDataType HeapTop(HP* PHP)
{
assert(PHP);
assert(PHP->size > 0);
return PHP->a[0];
}
9.判断堆是否为空
bool HeapEmpty(HP* PHP)
{
assert(PHP);
return PHP->size == 0;
}
10.建堆
//1.建堆向上
for(i=1;i<n;i++)
{
AdjustUp(a,i);//从第1个开始建
}
//2.建堆向下
for(i=(n-1-1)/2;i>=0;i--)
{
AdjustDown(a,n,i);//从第倒数第一个非叶子节点开始
}
11.建堆的时间复杂度
向下建堆的时间复杂度O(n)
向上建堆的时间复杂度O(n*logn)
12.堆排序
//升序 建大堆
//降序 建小堆
void HeapSort(int* a, int n)
{
assert(a);
// 建堆,先从最后两个叶子上的根(索引为(n - 2) / 2开始建堆
// 先建最小的堆,直到a[0](最大的堆)
// 这就相当于在已经建好的堆上面,新加入一个
// 根元素,然后向下调整,让整个完全二叉树
// 重新满足堆的性质
for (int i = (n - 2) / 2; i >= 0; --i)
{
AdjustDown(a, n, i);
}
//end:表示最后一个位置
int end = n - 1;
//只剩一个数时,就不需要调整了
while (end > 0)
{
//0位置和最后一个位置交换
swap(a[0], a[end]);
AdjustDown(a, end, 0);
--end;
}
}
三.TopK问题
void PrintTopK(int *a, int k, int n)
{
//建堆 用a中k个数建堆
int* KMinHeap = (int*)malloc(sizeof(int) * k);
for (int i = 0; i < k; i++)
{
KMinHeap[i] = a[i];
}
for (int i = (k - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(KMinHeap, k, i);
}
for (int j = k; j < n; j++)
{
if (a[j] > KMinHeap[0])
{
AdjustDown(KMinHeap, k, 0);
}
}
for (int i = 0; i < k; i++)
cout << KMinHeap[i]<<" ";
}
原文地址:https://www.jb51.cc/wenti/3281885.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。