Table of contents
4. The practical use of trees (representing the directory tree structure of the file system)
2. Concept and structure of binary tree
4. Storage structure of binary tree
3. The sequential structure and implementation of the binary tree
1. The sequential structure of the binary tree
2. The concept and structure of the heap
3.3 Upward adjustment of pile building
3.6 Other functions of the heap
4. Heap building time complexity
6. Implementation of binary tree chain structure
6.3 The number of nodes in a binary tree
6.7 Determine whether a binary tree is a complete binary tree
1. Tree concept and structure
1. The concept of a tree
- A tree is a non-linear data structure, which is composed of n ( n>=0 ) finite nodes to form a set with a hierarchical relationship. It is called a tree because it looks like an upside-down tree, which means it has the roots pointing up and the leaves pointing down .
- There is a special node called the root node, the root node has no predecessor node, except the root node, the other nodes are divided into M (M>0) disjoint sets T1 , T2 , ... , Tm , Each set Ti (1<= i <= m) is a subtree similar in structure to a tree. The root node of each subtree has one and only one predecessor, and can have zero or more successors. Therefore, the tree is defined recursively .
Note: In the tree structure, there can be no intersection between subtrees, otherwise it is not a tree structure
2. Related concepts of trees
- Degree of node : The number of subtrees contained in a node is called the degree of the node; as shown in the figure above: A is 6
- Leaf node or terminal node : A node with a degree of 0 is called a leaf node; as shown in the above figure: B , C , H , I... etc. are leaf nodes
- Non-terminal node or branch node : a node whose degree is not 0 ; as shown in the figure above: nodes such as D , E , F , G... are branch nodes
- Parent node or parent node : If a node contains child nodes, this node is called the parent node of its child nodes; as shown above: A is the parent node of B
- Child node or child node : the root node of the subtree contained in a node is called the child node of the node; as shown above: B is the child node of A
- Brother nodes : Nodes with the same parent node are called brother nodes; as shown in the above figure: B and C are brother nodes
- Degree of the tree : In a tree, the degree of the largest node is called the degree of the tree; as shown above: the degree of the tree is 6
- The level of nodes : starting from the definition of the root, the root is the first level , the child nodes of the root are the second level, and so on;
- Tree height or depth : the maximum level of nodes in the tree; as shown above: the height of the tree is 4
- Cousin nodes : Nodes whose parents are on the same layer are cousins; as shown in the above figure: H and I are sibling nodes
- Ancestors of a node : from the root to all nodes on the branches of the node; as shown in the figure above: A is the ancestor of all nodes
- Descendants : Any node in the subtree rooted at a node is called a descendant of the node. As shown above: all nodes are descendants of A
- Forest : A collection of m ( m>0 ) disjoint trees is called a forest;
3. Tree Representation
typedef int DataType;
struct Node
{
struct Node* _firstChild1; // 第一个孩子结点
struct Node* _pNextBrother; // 指向其下一个兄弟结点
DataType _data; // 结点中的数据域
};
4. The application of trees in practice (representing the directory tree structure of the file system)
2. Concept and structure of binary tree
1. Binary tree concept
A binary tree is a finite set of nodes that :1. or empty2. It consists of a root node plus two binary trees called left subtree and right subtree
As can be seen from the figure above:
1. There is no node with degree greater than 2 in the binary tree2. The subtrees of the binary tree are divided into left and right, and the order cannot be reversed, so the binary tree is an ordered tree
2. Special binary tree
1. Full binary tree : a binary tree, if the number of nodes in each layer reaches the maximum value, then this binary tree is a full binary tree. That is to say, if a binary tree has K layers and the total number of nodes is (2^k)-1, then it is a full binary tree.2. Complete binary tree : A complete binary tree is a very efficient data structure, and a complete binary tree is derived from a full binary tree. For a binary tree with a depth of K and n nodes, it is called a complete binary tree if and only if each node has a one-to- one correspondence with the nodes numbered from 1 to n in the full binary tree with a depth of K. It should be noted that a full binary tree is a special kind of complete binary tree.
3. Properties of Binary Trees
1. If the number of layers of the root node is specified as 1 , then there are at most 2^(i-1) nodes on the i-th layer of a non-empty binary tree .2. If the number of layers of the root node is specified as 1 , then the maximum number of nodes in a binary tree with a depth of h is (2^h)-1.3. For any binary tree , if the number of leaf nodes is 0 and the number of branch nodes is 2, then n₀=n₂+14. If the number of layers of the root node is specified as 1 , the depth of a full binary tree with n nodes , h=㏒₂(n+1) . (ps: ㏒₂(n+1) is log base 2, n+1 is logarithm )5. For a complete binary tree with n nodes, if all nodes are numbered from 0 in the order of the array from top to bottom and from left to right, then for the node with the serial number i :1. If i>0 , the parent number of the node at i position: (i-1)/2 ; i=0 , i is the root node number, no parent node2. If 2i+1<n , the left child number: 2i+1 , 2i+1>=n otherwise there is no left child3. If 2i+2<n , the serial number of the right child: 2i+2 , 2i+2>=n , otherwise there is no right child
4. Storage structure of binary tree
1. Sequential storage
2. Chain storage
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; // 当前节点值域
};
3. The sequential structure and implementation of the binary tree
1. The sequential structure of the binary tree
2. The concept and structure of the heap
If there is a set of key codes K={K₀, K₁, K₂, ..., K(n-1)}, store all its elements in a one-dimensional array in the order of a complete binary tree, and satisfy: Ki <=K(2*i+1) and Ki<=K(2*i+2) (Ki>=K(2*i+1) and Ki>=K(2*i+2))i=0 , 1, 2..., it is called a small heap (or a large heap). The heap with the largest root node is called the largest heap or large root heap, and the heap with the smallest root node is called the smallest heap or small root heap.
Properties of the heap:
- The value of a node in the heap is always not greater than or not less than the value of its parent node;
- The heap is always a complete binary tree.
3. Implementation of the heap
3.1 The structure of the heap
typedef int HpDataType;
typedef struct Heap
{
HpDataType* _a;
int _size;
int _capacity;
}Heap;
3.2 Heap creation
For the construction of the heap, I directly reuse the initialization and insertion of the heap. For the insertion, I use upward adjustment to build the heap. Whether it is a large or small heap, you can control it yourself.
//堆的初始化
void HeapInit(Heap* hp)
{
assert(hp);
hp->_a = NULL;
hp->_capacity = hp->_size = 0;
}
// 堆的构建
void HeapCreate(Heap* hp, HpDataType* a, int n)
{
assert(hp);
HeapInit(hp);
for(int i = 0;i < n;++i)
{
HeapPush(hp, a[i]);
}
}
//插入
void HeapPush(Heap* hp, HpDataType x)
{
assert(hp);
if (hp->_capacity == hp->_size)
{
HpDataType newcapacity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;
HpDataType* tmp = (HpDataType*)realloc(hp->_a, sizeof(HpDataType)* newcapacity);
if (tmp == NULL)
{
perror("malloc fail");
exit(-1);
}
hp->_a = tmp;
hp->_capacity = newcapacity;
}
hp->_a[hp->_size] = x;
hp->_size++;
Adjustup(hp->_a,hp->_size - 1);//向上调整建堆
}
3.3 Upward adjustment of pile building
Because after inserting a piece of data from the end, there may be problems with the post section of the heap, so an adjustment is made every time a piece of data is inserted.
If it is to build a small pile, start from the last position, and the last subscript must be the child, then if the value of the child's position is smaller than the value of the father's position, the values of the two should be exchanged, and then continue to go up.
//向上调整
void Adjustup(HpDataType* a,int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[child] < a[parent])//小堆
{
swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
3.4 Delete heap top data
Deleting the data at the top of the heap cannot directly delete the first data. If you directly delete the heap section, there will be problems, and you need to rebuild the heap later, which is time-consuming and laborious. So first exchange the data at the end with the data at the top of the heap, and then size--, the data is deleted. At this time, the data at the top of the heap is exchanged, which does not conform to the structure of the heap, and then the data at the top of the heap is down Tweak, tweak, and delete data is not done.
//删除堆顶数据
void HeapPop(Heap* hp)
{
assert(hp);
if (!HeapEmpty(hp))
{
swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
hp->_size--;
Adjustdown(hp->_a,hp->_size,0);
}
}
3.5 Down adjustment
Still take Jianxiaodui as an example, first look at the left and right children who are younger, and exchange whoever is younger. The child is smaller than the father, exchange and continue to go down until the structure of the heap is satisfied, and the adjustment is over.
//向下调整
void Adjustdown(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])
{
swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
3.6 Other functions of the heap
//显示堆的数据
void HeapPrint(Heap* hp)
{
assert(hp);
for(int i = 0;i < hp->_size;++i)
{
printf("%d ", hp->_a[i]);
}
printf("\n");
}
//交换
void swap(HpDataType* q1, HpDataType* q2)
{
HpDataType tmp = *q1;
*q1 = *q2;
*q2 = tmp;
}
//判断是否为空
bool HeapEmpty(Heap* hp)
{
assert(hp);
return hp->_size == 0;
}
//获取堆顶的数据
HpDataType HeapTop(Heap* hp)
{
assert(hp);
return hp->_a[0];
}
//堆的数据个数
int HeapSize(Heap* hp)
{
assert(hp);
return hp->_size;
}
//堆的销毁
void HeapDestry(Heap* hp)
{
assert(hp);
free(hp->_a);
hp->_capacity = hp->_size = 0;
}
4. Time complexity of building a heap
5. Application of the heap
5.1 Heap sort
// 对数组进行堆排序
void HeapSort(int* a, int n)
{
//升序建大堆,降序建小堆
for (int i = (n-2)/2; i >= 0; --i)
{
Adjustdown(a, n, i);
}
//先选出最大的或最小的,交换到数组尾部,向下调整后再选出次大或次小的再次交换到尾部位置的前一个位置
for (int i = 1; i < n; ++i)
{
swap(&a[0], &a[n - i]);
Adjustdown(a, n - i, 0);
}
}
5.2 TOP-K problem
//找n个数里最大或最小的前K个
void PrintTopK(int* a, int n, int k)
{
const char* filename = "test1.txt";
FILE* fout = fopen(filename, "r");
if (fout == NULL)
{
perror("fopen fail");
return;
}
for(int i = 0;i<k;++i)
{
fscanf(fout, "%d", &a[i]);
}
for (int i = (k - 2) / 2; i >= 0; --i)
{
Adjustdown(a, k, i);
}
int ret = 0;
while (fscanf(fout, "%d", &ret) != EOF)
{
if (ret > a[0])
{
a[0] = ret;
Adjustdown(a, k, 0);
}
}
//free(a);
fclose(fout);
}
//往文件里写数据
void WriteData(const char* filename, int n)
{
FILE* fin = fopen(filename, "w");
if (fin == NULL)
{
perror("fopen fail");
return;
}
srand(time(NULL));
while (n--)
{
fprintf(fin, "%d ", rand());
}
fclose(fin);
}
6. Implementation of binary tree chain structure
6.1 Structure of Binary Tree
Here is a review of the concept of a binary tree:
Binary tree is: 1. Empty tree , 2. Non-empty: root node, left subtree of root node, right subtree of root node.
It can be seen from the concept that the definition of a binary tree is recursive, so the basic operations in the subsequent order are basically implemented according to this concept.
//符号和结构的定义
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
6.2 Binary tree traversal
There are four types of binary tree traversals: preorder, inorder, postorder, and layer order.
The order of each traversal of the binary tree:Preorder: root, left subtree, right subtree;Inorder: left subtree, root, right subtree;Postorder: left subtree, right subtree, root;Layer sequence: first layer, second layer, Nth layer, (from left to right)
// 二叉树前序遍历
void BTPrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%c ", root->_Data);
BTPrevOrder(root->_Left);
BTPrevOrder(root->_Right);
}
// 二叉树中序遍历
void BTInOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
BTPrevOrder(root->_Left);
printf("%d ", root->_Data);
BTPrevOrder(root->_Right);
}
// 二叉树后序遍历
void BTPostOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
BTPrevOrder(root->_Left);
BTPrevOrder(root->_Right);
printf("%d ", root->_Data);
}
6.2 Building a binary tree
The data of the nodes here uses characters, and the numbers are the same, just change the custom type. Use preorder traversal to build a binary tree, use # to represent NULL, and assign the contents of the array a to each node in turn.
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
if (a[*pi] == '#')
{
(*pi)++;
return NULL;
}
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
if (root == NULL)
{
perror("malloc fail");
return NULL;
}
root->_Data = a[(*pi)++];
root->_Left = BinaryTreeCreate(a, pi);
root->_Right = BinaryTreeCreate(a, pi);
return root;
}
6.3 The number of nodes in a binary tree
// 二叉树节点个数
int BTSize(BTNode* root)
{
if (root == NULL)
return 0;
return BTSize(root->_Left) + BTSize(root->_Right) + 1;
}
// 二叉树叶子节点个数
int BTLeafSize(BTNode* root)
{
if (root == NULL)
return 0;
int leSize = BTLeafSize(root->_Left);
int riSize = BTLeafSize(root->_Right);
return leSize > riSize ? leSize + 1 : riSize + 1;
}
// 二叉树第k层节点个数
int BTLevelKSize(BTNode* root, int k)
{
assert(k > 0);
if (root == NULL)
return 0;
if (k == 1)
return 1;
return BTLevelKSize(root->_Left, k - 1) + BTLevelKSize(root->_Right, k - 1);
}
6.4 Finding Nodes
If it is found here, just return to the current node layer by layer. If the left subtree cannot be found, the right subtree cannot be found and needs to return empty.
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
return NULL;
if (root->_Data == x)
{
return root;
}
BTNode* lret = BinaryTreeFind(root->_Left, x);
if (lret != NULL)
return lret;
BTNode* rret = BinaryTreeFind(root->_Right, x);
if (rret != NULL)
return rret;
return NULL;
}
6.5 Destroy the binary tree
// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{
if (root == NULL)
return;
BinaryTreeDestory(root->_Left);
BinaryTreeDestory(root->_Right);
free(root);
}
6.6 Level order traversal
Queues are needed here, so you need to refer to the previous code.
// 层序遍历
void BTLevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);//队列初始化
if (root)
QueuePush(&q, root);//入队列
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);//获取队头
QueuePop(&q);//出队列
printf("%c ", front->_Data);
if(front->_Left)
QueuePush(&q, front->_Left);
if (front->_Right)
QueuePush(&q, front->_Right);
}
printf("\n");
QueueDestory(&q);//销毁队列
}
The code using the queue here needs to pay attention to putting the structure of the binary tree in the header file of the queue, otherwise the compilation report will not miss it.
6.7 Determine whether a binary tree is a complete binary tree
It is to traverse the binary tree with the method of layer-order traversal, enter the root first, and leave the queue if the root is not empty. At the same time, let its left and right subtrees also enter the queue, and traverse until the first empty one is encountered, then it must be followed by empty, otherwise it is not a complete binary tree.
// 判断二叉树是否是完全二叉树
int BTComplete(BTNode* root)
{
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)
{
QueueDestory(&q);
return false;
}
}
QueueDestory(&q);
return true;
}
Complete code: Binary/Binary The evening wind is not as good as your smile/homework library- Code Cloud- Open Source China (gitee.com)