数据结构-树
二叉树概念
分类:
1.空的二叉树:就结构体指针 tree=NULL
2.只有根节点的二叉树 (只有一个结点)
3.只有左子树或者右子树的二叉树
4.左右子树都存在:完全二叉树,满二叉树(编号是按顺序的)
注:红色的点是父节点,绿色的是孩节点(孩节点/2=父节点)
[{"url":"https://image-1309791158.cos.ap-guangzhou.myqcloud.com/%E5%85%B6%E4%BB%96%2FbsyPbV.png","alt":""},{"url":"https://image-1309791158.cos.ap-guangzhou.myqcloud.com/%E5%85%B6%E4%BB%96%2Fbsy9uq.png","alt":""},{"url":"https://image-1309791158.cos.ap-guangzhou.myqcloud.com/%E5%85%B6%E4%BB%96%2FbsyCD0.png","alt":""},{"url":"https://image-1309791158.cos.ap-guangzhou.myqcloud.com/%E5%85%B6%E4%BB%96%2FbsyFET.png","alt":""}]
别名:LPSTR:char* LPCSTR: const char* (定义别名用LP表示指针)
main.cpp
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
typedef struct treeNode
{
char data;//数据域用字符表示
struct treeNode* LCHild;
struct treeNode* RCHild;
}TREE,*LPTREE;
LPTREE createNode(char data)
{
LPTREE newNode = (LPTREE)malloc(sizeof(TREE));
if (!newNode)
{
printf("创建新节点失败!");
exit(0);
}
else
{
newNode->data = data;
newNode->LCHild = NULL;
newNode->RCHild = NULL;
return newNode;
}
}
//没有规律的树
void insertNode(LPTREE parentNode, LPTREE LCHild, LPTREE RCHild)
{
parentNode->LCHild = LCHild;
parentNode->RCHild = RCHild;
}
//打印当前节点中的元素
void print(LPTREE curData)
{
printf("%c ", curData->data);
}
//递归,前序
void preOrder(LPTREE root)
{
if (root != NULL)
{
print(root);//根
preOrder(root->LCHild);//左
preOrder(root->RCHild);//右
}
}
//中序
//递归
void preOrder2(LPTREE root)
{
if (root != NULL)
{
preOrder2(root->LCHild);//左
print(root);//根
preOrder2(root->RCHild);//右
}
}
//后序
//递归
void preOrder3(LPTREE root)
{
if (root != NULL)
{
preOrder3(root->LCHild);//左
preOrder3(root->RCHild);//右
print(root);//根
}
}
int main()
{
//死板的创建过程,无实际作用
LPTREE A = createNode('A');
LPTREE B = createNode('B');
LPTREE C = createNode('C');
LPTREE D = createNode('D');
LPTREE E = createNode('E');
LPTREE F = createNode('F');
LPTREE G = createNode('G');
insertNode(A, B, C);
insertNode(B, D, NULL);
insertNode(D, NULL, G);
insertNode(C, E, F);
printf("先序:");
preOrder(A);
printf("\n中序:");
preOrder2(A);
printf("\n后序:");
preOrder3(A);
return 0;
}
先序流程
main.cpp
void preOderBystack(LPTREE root)
{
if (root == NULL)
return;
//准备入栈
struct treeNode* stack[10];//存储每次打印节点的位置
int stackTop = -1;//栈顶标记
LPTREE pMove = root;//从根节点开始打印
while (stackTop != -1 || pMove)
{
while (pMove)
{
//把路径入栈+打印走过的节点
printf("%c ", pMove->data);
stack[++stackTop] = pMove;
pMove = pMove->LCHild;
}
//无路可走
if (stackTop != -1)
{
pMove = stack[stackTop];//获取栈顶元素
stackTop--;//出栈
pMove = pMove->RCHild;
}
}
}
中序流程
main.cpp
//中序
void preOderBystack2(LPTREE root)
{
if (root == NULL)
return;
struct treeNode* stack[10];
int stackTop = -1;
LPTREE pMove = root;
while (stackTop != -1 || pMove)
{
while (pMove)
{
stack[++stackTop] = pMove;
pMove = pMove->LCHild;
}
//出栈
if (stackTop != -1)
{
pMove = stack[stackTop--];
printf("%c ", pMove->data);
pMove = pMove->RCHild;
}
}
}
后序流程
main.cpp
void preOderBystack3(LPTREE root)
{
if (root == NULL)
return;
struct treeNode* stack[10];
int stackTop = -1;
struct treeNode* pMove = root;
struct treeNode* plastVisit = NULL;//访问标记
//左 右 根
//pMove一直来到最左下角
while (pMove)
{
stack[++stackTop] = pMove;
pMove = pMove->LCHild;
}
//开始出栈,判断右边是否有节点是否被访问过
while (stackTop != -1)
{
pMove = stack[stackTop--];
//当前节点左右是否被访问
if (pMove->RCHild == NULL || pMove->RCHild == plastVisit)
{
//如果被访问就可以打印当前节点数据
printf("%c ", pMove->data);
plastVisit = pMove;//改变标记位置
}
else
{
//右边没有被访问
stack[++stackTop] = pMove;
pMove = pMove->RCHild;
while (pMove)
{
stack[++stackTop] = pMove;
pMove = pMove->LCHild;
}
}
}
}
main函数
main.cpp
int main()
{
//死板的创建过程,无实际作用
LPTREE A = createNode('A');
LPTREE B = createNode('B');
LPTREE C = createNode('C');
LPTREE D = createNode('D');
LPTREE E = createNode('E');
LPTREE F = createNode('F');
LPTREE G = createNode('G');
insertNode(A, B, C);
insertNode(B, D, E);
insertNode(C, F, G);
printf("先序:");
preOderBystack(A);
printf("\n中序:");
preOderBystack2(A);
printf("\n后序:");
preOderBystack3(A);
}
二叉树:节点和边上的数学特性
深度:几层
1.第i层最多有2^(i-1)个节点
2.二叉树深度是i,最多有多少个节点:2^i-1
3.假设二叉树有n个节点,二叉树最小深度是:log₂(n+1)
大顶堆
入堆
main.cpp
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# define MAX 10
typedef struct Heap
{
int sizeHeap;
int* heapData;
}HEAP,*LPHEAP;
//创建堆
LPHEAP createHeap()
{
LPHEAP heap = (LPHEAP)malloc(sizeof(HEAP));
heap->sizeHeap = 0;
heap->heapData = (int*)malloc(sizeof(int) * MAX);
return heap;
}
//万金油
int size(LPHEAP heap)
{
return heap->sizeHeap;
}
int empty(LPHEAP heap)
{
//返回1 表示NULL 返回0 表示不为NULL
return heap->sizeHeap == 0;
}
void moveTocrrectPos(LPHEAP heap, int curPos)
{
//向上渗透
while (curPos > 1)//渗透到下标是1的位置,表示结束
{
int Max = heap->heapData[curPos];//比较
int parentIndex = curPos / 2;
if (Max > heap->heapData[parentIndex])
{
//交换孩子点和父节点的值
heap->heapData[curPos] = heap->heapData[parentIndex];
heap->heapData[parentIndex] = Max;
curPos = parentIndex;
}
else
break;//不需要调整
}
}
//入堆
void insertHeap(LPHEAP heap, int data)
{
//放到当前堆的最后面
++heap->sizeHeap;
heap->heapData[heap->sizeHeap] = data;
//大顶堆,调整当前元素的位置
moveTocrrectPos(heap, heap->sizeHeap);
}
int main()
{
LPHEAP heap = createHeap();
//数组下标[0]那段内存不会去用!!!!
for (int i = 1; i < 11; i++)
{
insertHeap(heap, i);
}
for (int i = 1; i < 11; i++)
{
printf("%d ", heap->heapData[i]);
}
printf("\n");
return 0;
}
出堆
main.cpp
int popHeap(LPHEAP heap)
{
int Max = heap->heapData[1];
//调整堆,向下渗透,找最后一个适合的位置的下标
int curPos = 1;
int childIndex = curPos * 2;
while (childIndex <= heap->sizeHeap)
{
int temp = heap->heapData[childIndex];
//同一层上面需要左右比较
if (childIndex + 1 <= heap->sizeHeap && temp < heap->heapData[childIndex + 1])
{
temp = heap->heapData[++childIndex];//等效于childIndex+1
}
heap->heapData[curPos] = temp;
curPos = childIndex;
childIndex*= 2;
}
heap->heapData[curPos] = heap->heapData[heap->sizeHeap];
--heap->sizeHeap;
return Max;
}
main.cpp(打印)
while (!empty(heap))
{
printf("%d ", popHeap(heap));
}