目录
树是一种非线性数据结构,顶端是根节点,最底端是叶子结点,像是棵倒立的树
树的概念
子节点:以某节点为根的节点(如,B,C是A的子节点)
叶结点:在树中没有子节点的叫做叶子节点(如,D,E,F,G)
节点的度:一个节点拥有的所有子节点的个数(子孙结点不算)
树的度:在一个树中最大节点的度叫树的度(如,A的度为2)
节点层次:从根开始,根为一,根的子节点为第二层
树的高度或深度:树中节点的最大层次(如图为三层)
森林:互不相交的树的集合
子孙:以某节点为根的子树都可以叫做子孙(所有节点都是A节点的子孙)
根节点:没有父节点的节点
节点的祖先:从根节点到祖先这条路径上的所有节点(如A节点是左右节点的祖先)
......
二叉树的概念
二叉树度最大为二,分为左节点和右节点,子树与子树之间不能相交
次序不能颠倒,因此二叉树是有序树
树的定义
左孩子右兄弟表示法
typedef struct BinaryTreeNode
{
BTDataType val;
struct BinaryTreeNode* child;
struct BinaryTreeNode* brothers;
}BTNode;
如图A有左孩子B和右孩子C两个子节点,B又有左孩子D和右孩子E两个子节点,以此类推
typedef struct BinaryTreeNode
{
BTDataType val;
//左节点
struct BinaryTreeNode* left;
//右节点
struct BinaryTreeNode* right;
}BTNode;
满二叉树
满二叉树每层的节点都是满的
当满二叉树深度为h层时,总结点个数是2^h-1个
完全二叉树
完全二叉树最后一层可以不满,但是最后一层从左向右是连续的(完全二叉树可以是满二叉树,但是,满二叉树一定不能是完全二叉树)
当完全二叉树的高度为h层时,完全二叉树节点最多是2^h-1个,最少是2^(h-1)个
堆
此堆非彼堆,这个堆是一种数据结构与操作系统中的堆没有关系
这个堆是二叉树的一种存储结构是使用顺序结构数组来存储数据的,但只适合完全二叉树,因为使用堆这个结构其实就是用下标来访问数据,而其他二叉树由于特殊或是其特可能导致有的地方没有数据,从而导致空间的浪费
堆有两种结构
大堆:任何一个父节点都大于等于子节点
小堆:任何一个父节点都要小于子节点
堆在内存中的真实存储方式是物理结构,如上图数组
而图中二叉树就是我们想想出来的逻辑结构
左孩子=父节点*2+1
右孩子=父节点*2+2
父节点=孩子-1/2
堆的实现
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#define HPcapacity 4
typedef int HPDatatype;
//数组结构
typedef struct Heap
{
HPDatatype* a;
int size;
int capacity;
}HP;
//初始化
void HeaPInit(HP* php);
//销毁
void HeaPDestroy(HP* php);
//判空
bool HeaPEmpty(HP* php);
//向上调整
void HeaPjustup(HPDatatype* a,int x);
//向下调整
void HeaPjustDown(HPDatatype* a, int n, int parent);
//插入
void HeaPPush(HP* php, HPDatatype x);
//堆的数据个数
int HeaPSize(HP* php);
//堆的删除
void HeaPPop(HP* php);
//返回堆顶数据
HPDatatype HeaPTop(HP* php);
//交换函数
void HeaPSwap(HPDatatype* p1, HPDatatype* p2);
//堆排
void HeapSort(HPDatatype * a, int n);
//初始化
void HeaPInit(HP* php)
{
assert(php);
php->a = NULL;
php->size = php->capacity = 0;
}
//判空
bool HeaPEmpty(HP* php)
{
assert(php);
return php->size == 0;
}
//销毁
void HeaPDestroy(HP* php)
{
assert(php);
free(php->a);
php->size = php->capacity = 0;
}
//插入
void HeaPPush(HP* php, HPDatatype x)
{
assert(php);
if (php->size == php->capacity)
{
int tmp = 0;
tmp = php->capacity == 0 ? 4 : php->capacity*2;
HPDatatype* ptr = (HPDatatype*)realloc(php->a,sizeof(HPDatatype) * tmp);
if (ptr == NULL)
{
perror("malloc fail");
return;
}
php->a = ptr;
php->capacity = tmp;
}
php->a[php->size++] = x;
HeaPjustup(php->a, php->size - 1);
}
//交换函数
void HeaPSwap(HPDatatype* p1, HPDatatype* p2)
{
HPDatatype tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
//堆的数据个数
int HeaPSize(HP* php)
{
assert(php);
return php->size;
}
//向上调整
void HeaPjustup(HPDatatype* a,int child)
{
int parent = (child-1) / 2;
while (child>0)
{
if (a[child] > a[parent])
{
HeaPSwap(&a[child], &a[parent]);
//替换父子位置
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
//向下调整(注意使用向下调整左右节点必须是大堆或小堆)
void HeaPjustDown(HPDatatype* a,int n, int parent)
{
int child = parent * 2 + 1;
//父节点小于总结点
while (child < n)
{
//选出左右孩子最大或最小的
//防止没有右节点
if (child+1<=n&&a[child] < a[child + 1])
{
child++;
}
//将大的数向下调整
if (a[child] > a[parent])
{
HeaPSwap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//删除
void HeaPPop(HP* php)
{
assert(php);
assert(!HeaPEmpty(php));
//首尾交换删除
HeaPSwap(&php->a[0], &php->a[php->size - 1]);
php->size--;
//向下调整
HeaPjustDown(php->a, php->size, 0);
}
//返回堆顶元素
HPDatatype HeaPTop(HP* php)
{
assert(php);
assert(!HeaPEmpty(php));
return php->a[0];
}
//堆排序
void HeapSort(HPDatatype* a, int n)
{
//利用向下排序建堆
int j = (n - 2) / 2;
int end = n - 1;
while (j>=0)
{
HeaPjustDown(a, n, j);
--j;
}
while (end>0)
{
HeaPSwap(&(a[0]), &(a[end]));
HeaPjustDown(a, --end, 0);
}
}
链式二叉树
链式二叉树单纯存储数据是没有意义的
链式二叉数结构的定义
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
//左节点
struct BinaryTreeNode* left;
//右节点
struct BinaryTreeNode* right;
}BTNode;
链式二叉树是以递归来实现的
分为前序,中序,后序,层序
前序:先访问根再访问左子树,右子树
中序:先访问左子树,根,右子树
层序:先访问左子树,右子树,根
层序:使用队列,每次根节点出队列,会将子节点带入队列
链式二叉树的实现
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef char BTDataType;
//定义一个二叉树的结构
typedef struct BinaryTreeNode
{
BTDataType val;
//左节点
struct BinaryTreeNode* left;
//右节点
struct BinaryTreeNode* right;
}BTNode;
typedef struct BinaryTreeNode
{
BTDataType val;
struct BinaryTreeNode* child;
struct BinaryTreeNode* brothers;
}BTNode;
//二叉树的创建
BTNode* BTCreate(BTDataType* a, int* pi);
//二叉树的销毁
void BTDestroy(BTNode* root);
//二叉树的节点个数
int BTSize(BTNode* root);
//二叉树的叶子结点个数
int BTLeaf(BTNode* root);
//二叉树第k层节点个数
int BTLevelKSize(BTNode* root, int k);
//查找二叉树值为x的节点
BTNode* BTFind(BTNode* root, BTDataType x);
//二叉树前序遍历
void BTPrevOrder(BTNode* root);
//二叉树中序遍历
void BTInOrder(BTNode* root);
//二叉树后序遍历
void BTPostOrder(BTNode* root);
BTNode* BTCreate(BTDataType* a, int* pi)
{
//if (*pi >= n || *pi + 1 > n)
//{
// return NULL;
//}
//BTNode* Node = (BTNode*)malloc(sizeof(BTNode));
//if (Node == NULL)
//{
// perror("malloc fail");
// return NULL;
//}
//Node->val = a[*pi];
//int i = 0;
//i = (*pi) * 2 + 1;
printf("%d ", Node->val);
//Node->left = BTCreate(a, n, &i);
//i = i + 1;
//Node->right = BTCreate(a, n, &i);
//return Node;
if (a[*pi] == '#')
{
(* pi)++;
return NULL;
}
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
if (root == NULL)
{
perror("malloc fail");
return NULL;
}
root->val = a[*pi];
(* pi)++;
printf("%c ", root->val);
root->left=BTCreate(a, pi);
root->right=BTCreate(a, pi);
return root;
}
void BTDestroy(BTNode* root)
{
if (root == NULL)
{
return;
}
BTDestroy(root->left);
BTDestroy(root->right);
free(root);
root = NULL;
}
int BTSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
return BTSize(root->left) + BTSize(root->right)+1;
}
int x = 0;
int BTLeaf(BTNode* root)
{
if (root == NULL)
{
return 0;
}
if (root->left == NULL && root->right==NULL)
return 1;
///*if (L + R == 0)
//{
// return 1;
//}*/
//int num = L + R;
return BTLeaf(root->right) + BTLeaf(root->left);
}
int BTLevelKSize(BTNode* root, int k)
{
assert(k);
if (root == NULL)
{
return 0;
}
if (k==1)
{
return 1;
}
return BTLevelKSize(root->left,k-1) + BTLevelKSize(root->right, k - 1) ;
}
BTNode* BTFind(BTNode* root, BTDataType x)
{
if (root == NULL)
{
return NULL;
}
if (root->val == x)
{
return root;
}
BTNode* Left = BTFind(root->left,x);
if (Left)
{
return Left;
}
BTNode* Right = BTFind(root->right, x);
if (Right)
{
return Right;
}
return NULL;
}
void BTPrevOrder(BTNode* root)
{
//前序遍历,根,左,右
if (root == NULL)
{
return NULL;
}
printf("%d ", root->val);
BTPrevOrder(root->left);
BTPrevOrder(root->right);
return NULL;
}
void BTInOrder(BTNode* root)
{
//中序遍历,左,根,右
if (root == NULL)
{
return NULL;
}
BTPrevOrder(root->left);
printf("%d ", root->val);
BTPrevOrder(root->right);
return NULL;
}
void BTPostOrder(BTNode* root)
{
//后序遍历,左,右,根
if (root == NULL)
{
return NULL;
}
BTPostOrder(root->left);
BTPostOrder(root->right);
printf("%d ", root->val);
return NULL;
}
//判断是否为完全二叉树
bool BTComplete(BTNode* root)
{
//层序遍历
Queue Q;
QuInit(&Q);
if (root)
QuPush(&Q,root);
while (!QuEmpty(&Q))
{
BTNode* BT =QuFront(&Q);
QuPop(&Q);
if (BT==NULL)
{
break;
}
QuPush(&Q, BT->left);
QuPush(&Q, BT->right);
}
while (!QuEmpty(&Q))
{
BTNode* BT = QuFront(&Q);
QuPop(&Q);
if (BT)
{
QuDestroy(&Q);
return false;
}
}
QuDestroy(&Q);
return true;
}
层序遍历
void BTLevelOrder(BTNode* root)
{
//队列实现层序遍历
Queue Q;
//队列初始化
QuInit(&Q);
//根为真push节点进队列
if(root)
QuPush(&Q, root);
while (!QuEmpty(&Q))
{
//取出队头数据
BTNode* r=QuFront(&Q);
//删除数据
QuPop(&Q);
printf("%d ", r->val);
//把前一个节点的左右子树带入队列
if (r->left)
{
QuPush(&Q, r->left);
}
if (r->right)
{
QuPush(&Q, r->right);
}
}
//销毁
QuDestroy(&Q);
}