树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。
把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
有一个特殊的结点,称为根结点,根节点没有前驱结点
除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti (1<= i <= m) 又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
因此,树是递归定义的。
注意:树形结构中,子树之间不能有交集,否则就不是树形结构
节点的度:
一个节点含有的子树的个数称为该节点的度; 如上图:A的度为6
叶子节点或终端节点:
度为0的节点称为叶节点; 如上图:B、C、H…等节点为叶子节点
非终端节点或分支节点:
度不为0的节点; 如上图:D、E、F…等节点为分支节点
双亲节点或父节点:
若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点
孩子节点或子节点:
一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
兄弟节点:
具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点
树的度:
一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
节点的层次:
从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:
树中节点的最大层次; 如上图:树的高度为4
堂兄弟节点:
双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
节点的祖先:
从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
子孙:
以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
森林:
由m(m>0)棵互不相交的树的集合称为森林;
树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,既要保存数据域,又要保存结点和结点之间的关系。
实际中树有很多种表示方式如:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法等。我们这里就简单的了解其中最常用的孩子兄弟表示法。
typedef int DataType;
struct Node
{
struct Node* firstChild; // 第一个孩子结点
struct Node* pNextBrother; // 指向其下一个兄弟结点
DataType data; // 结点中的数据域
};
一棵二叉树是结点的一个有限集合,该集合:
从上图看出:
满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。换言之,如果一个二叉树的层数为K,且结点总数是 2k - 1,则它就是满二叉树。
完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树衍生出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一 一对应时称之为完全二叉树(简单理解:前K - 1层满,第K层不满)。 要注意的是满二叉树是一种特殊的完全二叉树。
- 若i > 0,i 位置节点的双亲序号:(i - 1) / 2
- i = 0,i 为根节点编号,无双亲节点
- 若2i+1 < n,左孩子序号:2i + 1,2i + 1 >= n 则无左孩子
- 若2i+2 < n,右孩子序号:2i + 2,2i + 2 >= n 则无右孩子
二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。
typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{
struct BinTreeNode* pLeft; // 指向当前节点左孩子
struct BinTreeNode* pRight; // 指向当前节点右孩子
BTDataType data; // 当前节点值域
};
// 三叉链
struct BinaryTreeNode
{
struct BinTreeNode* pParent; // 指向当前节点的双亲
struct BinTreeNode* pLeft; // 指向当前节点左孩子
struct BinTreeNode* pRight; // 指向当前节点右孩子
BTDataType data; // 当前节点值域
};
普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储。
这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。
如果有一个集合 K = { k0 ,k1 ,k2 …,kn-1 },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中
并满足:Ki <= K2*i+1 且 Ki <= K2*i+2 (Ki >= K2*i+1 且 Ki >= K2*i+2 ) i = 0,1,
2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
int array[] = {27,15,19,18,28,34,65,49,25,37};
int array[] = {1,5,3,8,7,6};
void HeapInit(Heap* php)
{
assert(php);
php->a = NULL;
php->size = php->capacity = 0;
}
void HeapDestory(Heap* php)
{
assert(php);
free(php->a);
php->a = NULL;
php->size = php->capacity = 0;
}
void Swap(HPDataType* x, HPDataType* y)
{
HPDataType tmp = *x;
*x = *y;
*y = tmp;
}
void AdjustUp(HPDataType* a, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
//if (a[child] > a[parent])// > 建大堆
if (a[child] < a[parent])// < 建小堆
{
Swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void HeapPush(Heap* php, HPDataType x)
{
//插到最后 -- logN
if (php->size == php->capacity)
{
int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newCapacity);
if (NULL == tmp)
{
perror("malloc failed\n");
return;
}
php->a = tmp;
php->capacity = newCapacity;
}
php->a[php->size] = x;
php->size++;
//最后一个向上调整
AdjustUp(php->a, php->size - 1);
}
void AdjustDown(HPDataType* a, int n,int parent)
{
int minChild = parent * 2 + 1;
while (minChild < n)
{
//找大
//if (minChild + 1 < n && a[minChild + 1] > a[minChild])// > 建大堆(找大)
//找小
if (minChild + 1 < n && a[minChild + 1] < a[minChild])// < 建小堆(找小)
{
++minChild;
}
//if (a[parent] < a[minChild])// < 建大堆
if (a[parent] > a[minChild])// > 建小堆
{
Swap(&a[parent], &a[minChild]);
parent = minChild;
minChild = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapPop(Heap* php)
{
assert(php);
assert(!HeapEmpty(php));
//第一个和最后一个交换
Swap(&php->a[0], &php->a[php->size - 1]);
php->size--;
//第一个向下调整
AdjustDown(php->a,php->size,0);
}
HPDataType HeapTop(Heap* php)
{
assert(php);
assert(!HeapEmpty(php));
return php->a[0];
}
int HeapSize(Heap* php)
{
assert(php);
return php->size;
}
int HeapEmpty(Heap* php)
{
assert(php);
return php->size == 0;
}
void HeapPrint(Heap* php)
{
for (int i = 0; i < php->size; ++i)
{
printf("%d ", php->a[i]);
}
printf("\n");
}
// 找最大的前K个,建立K个数的小堆
// 找最小的前K个,建立K个数的大堆
void PrintTopK(int* a, int n, int k)
{
//求最大的前K个
//前K个建小堆
//后n - K个比堆顶大的交换,再向下调整
//建小堆
for (int i = (n - 2) / 2; i >= 0; --i)
{
AdjustDown(a, k, i);
}
//求最小的前K个
// 前K个建大堆
//后n - K个比堆顶小的交换,再向下调整
//建大堆 --> 向上、向下调整算法要改 !!!
//for (int i = (n - 2) / 2; i >= 0; --i)
//{
// AdjustDown(a, k, i);
//}
for (int i = k; i < n; ++i)
{
if (a[i] > a[0])
{
Swap(&a[i], &a[0]);
AdjustDown(a, k, 0);
}
}
for (int i = 0; i < k; ++i)
{
printf("%d ", a[i]);
}
}
// 对数组进行堆排序
void HeapSort(int* a, int n)
{
//升序:建大堆
//降序:建小堆
//向上调整建堆 O(N*logN)
//把第一个看作堆
//for (int i = 1; i < n; ++i)
//{
// AdjustUp(a, i);
//}
//建大堆
//向下调整建堆 O(N)
//从倒数第一个非叶子节点开始调
// (n - 1 - 1) / 2是最后一个节点的父亲
for (int i = (n - 1 - 1) / 2; i >= 0; --i)
{
AdjustDown(a, n, i);
}
//选择排序
//每次第一个(最大)和最后一个交换,再把最后一个的位置提前一个
for (int i = 0; i < n; ++i)
{
Swap(&a[0], &a[n - i - 1]);
AdjustDown(a, n - i - 1, 0);
}
}
#pragma once
#include
#include
#include
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a;
int size;
int capacity;
}Heap;
void HeapInit(Heap* php);
// 堆的构建
//void HeapCreate(Heap* php, HPDataType* a, int n);
// 堆的销毁
void HeapDestory(Heap* php);
// 堆的插入
void HeapPush(Heap* php, HPDataType x);
// 堆的删除
void HeapPop(Heap* php);
// 取堆顶的数据
HPDataType HeapTop(Heap* php);
// 堆的数据个数
int HeapSize(Heap* php);
// 堆的判空
int HeapEmpty(Heap* php);
void HeapPrint(Heap* php);
// TopK问题:找出N个数里面最大/最小的前K个问题。
// 比如:区排名前10的泡馍,西安交通大学王者荣耀排名前10的韩信,全国排名前10的李白。等等问题都是Topk问题,
// 需要注意:
// 找最大的前K个,建立K个数的小堆
// 找最小的前K个,建立K个数的大堆
void PrintTopK(int* a, int n, int k);
// 对数组进行堆排序
void HeapSort(int* a, int n);
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
//ABD##E#H##CF##G##
if (a[*pi] == '#')
{
(*pi)++;
return NULL;
}
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
if (root == NULL)
{
perror("malloc failed\n");
return NULL;
}
root->val = a[*pi];
(*pi)++;
root->left = BinaryTreeCreate(a, pi);
root->right = BinaryTreeCreate(a, pi);
return root;
}
BTNode* CreateTree()
{
BTNode* n1 = (BTNode*)malloc(sizeof(BTNode));
assert(n1);
BTNode* n2 = (BTNode*)malloc(sizeof(BTNode));
assert(n2);
BTNode* n3 = (BTNode*)malloc(sizeof(BTNode));
assert(n3);
BTNode* n4 = (BTNode*)malloc(sizeof(BTNode));
assert(n4);
BTNode* n5 = (BTNode*)malloc(sizeof(BTNode));
assert(n5);
BTNode* n6 = (BTNode*)malloc(sizeof(BTNode));
assert(n6);
n1->val = 1;
n2->val = 2;
n3->val = 3;
n4->val = 4;
n5->val = 5;
n6->val = 6;
n1->left = n2;
n1->right = n4;
n2->left = n3;
n2->right = NULL;
n4->left = n5;
n4->right = n6;
n3->left = NULL;
n3->right = NULL;
n5->left = NULL;
n5->right = NULL;
n6->left = NULL;
n6->right = NULL;
return n1;
}
void BinaryTreePrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
//根 左 右
printf("%d ", root->val);
BinaryTreePrevOrder(root->left);
BinaryTreePrevOrder(root->right);
}
void BinaryTreeInOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
// 左 根 右
BinaryTreeInOrder(root->left);
printf("%d ", root->val);
BinaryTreeInOrder(root->right);
}
void BinaryTreePostOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
//左 右 根
BinaryTreePostOrder(root->left);
BinaryTreePostOrder(root->right);
printf("%d ", root->val);
}
void BinaryTreeLevelOrder(BTNode* root)
{
//队列的val数据类型是BTNode*
Queue q;
QueueInit(&q);
if (root)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
printf("%d ", front->val);
// 下一层,入队列
if (front->left)
QueuePush(&q, front->left);
if (front->right)
QueuePush(&q, front->right);
}
printf("\n");
QueueDestroy(&q);
}
int BinaryTreeComplete(BTNode* root)
{
//队列的val数据类型是BTNode*
Queue q;
QueueInit(&q);
if (root)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front == NULL)
{
break;
}
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
// 遇到空以后,后面全是空,则是完全二叉树
// 遇到空以后,后面存在非空,则不是完全二叉树
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front != NULL)
{
QueueDestroy(&q);
return false;
}
}
QueueDestroy(&q);
return true;
}
int BinaryTreeSize(BTNode* root)
{
//if (root == NULL)
//{
// return 0;
//}
//else
//{
// return BinaryTreeSize(root->left)
// + BinaryTreeSize(root->right) + 1;
//}
return root == NULL ? 0 : BinaryTreeSize(root->left)
+ BinaryTreeSize(root->right) + 1;
}
int BinaryTreeLeafSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
//左右孩子都为空,叶子节点 +1
if (root->left == NULL && root->right == NULL)
{
return 1;
}
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
int BinaryTreeLevelKSize(BTNode* root, int k)
{
assert(k > 0);
if (root == NULL)
return 0;
if (k == 1)
return 1;
// 转换成求子树第k-1层
return BinaryTreeLevelKSize(root->left, k - 1)
+ BinaryTreeLevelKSize(root->right, k - 1);
}
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
BTNode* lret, * rret;
if (root == NULL)
return NULL;
if (root->val == x)
return root;
// 先去左树找
lret = BinaryTreeFind(root->left, x);
if (lret)
return lret;
// 左树没有找到,再到右树找
rret = BinaryTreeFind(root->right, x);
if (rret)
return rret;
return NULL;
}
int BinaryTreeHeight(BTNode* root)
{
if (root == NULL)
return 0;
int lh = BinaryTreeHeight(root->left);
int rh = BinaryTreeHeight(root->right);
return lh > rh ? lh + 1 : rh + 1;
}
void BinaryTreeDestory(BTNode** root)
{
if (*root == NULL)
{
return;
}
BinaryTreeDestory(&((*root)->left));
BinaryTreeDestory(&((*root)->right));
//左右孩子都为空就释放
free(*root);
*root = NULL;
}