二叉树概念

分类:

1.空的二叉树:就结构体指针 tree=NULL

2.只有根节点的二叉树 (只有一个结点)

3.只有左子树或者右子树的二叉树

4.左右子树都存在:完全二叉树,满二叉树(编号是按顺序的)

注:红色的点是父节点,绿色的是孩节点(孩节点/2=父节点)

别名: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));
	}