算法
- 1.单值二叉树
- 2.相同的树
- 3.另一棵树的子树
- 4.二叉树的前序遍历
- 5.二叉树的中序遍历
- 6.二叉树的后序遍历
- 7.二叉树遍历
- 8.TopK问题
1.单值二叉树
单值二叉树
思路
比较父节点和子结点,相同返回true,否则返回false,递归
设计程序
若结点为空返回true
遍历左子树和右子树,左子树中子结点和父节点相同且右子树中子结点和父子树相同返回true,其余全部返回false
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
typedef struct TreeNode TreeNode;
bool isUnivalTree(struct TreeNode* root) {
if(root==NULL)
return true;
if(root->left&&root->val!=root->left->val)
return false;
if(root->right&&root->val!=root->right->val)
return false;
return isUnivalTree(root->left)&&isUnivalTree(root->right);
}
不能以相同返回为真去判断,这样的话只遍历到根结点就会直接返回true了
2.相同的树
相同的树
思路
比较两个二叉树结点的值,不同返回false
设计程序
若两个结点同时为空返回true,其中一个为空返回false,都不为空则比较结点的值不同返回false,递归的遍历两个二叉树的左子树且右子树
编写代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
if(p==NULL&&q==NULL)
return true;
if(p==NULL||q==NULL)
return false;
if(p->val!=q->val)
return false;
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
对称二叉树
比较根节点的左子树和右子树是否相同,利用上题相同的树的接口
编写程序
直接调用相同的树函数,不过注意这里是对称不是相同,比较的结点是左子树的左结点和右子树的右结点且左子树的右结点且右子树的左结点
编写代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
if(p==NULL&&q==NULL)
return true;
if(p==NULL||q==NULL)
return false;
if(p->val!=q->val)
return false;
return isSameTree(p->left,q->right)&&isSameTree(p->right,q->left);
}
bool isSymmetric(struct TreeNode* root) {
return isSameTree(root->left,root->right);
}
3.另一棵树的子树
另一棵树的子树
思路
借用相同的树的代码遍历所有子树
设计程序
比较根节点和子树,比较根节点的左子树与子树或根节点的右子树与子树
编写代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
if(p==NULL&&q==NULL)
return true;
if(p==NULL||q==NULL)
return false;
if(p->val!=q->val)
return false;
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
if(root==NULL)
return false;
if(isSameTree(root,subRoot))
return true;
return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}
这里的话有些同学可能想当然return isSameTree(root->left,subRoot) || isSameTreeroot->right,subRoot);但其实这样的话只比较了层数为1和2的子树
4.二叉树的前序遍历
二叉树的前序遍历
思路 前序遍历,存放到数组中
设计程序
先确定数组大小封装一个求二叉树结点多少的接口,动态开辟相应大小的数组,前序遍历(单独封装)存放到数组中
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
typedef struct TreeNode TreeNode;
int BinaryTreeSize(TreeNode*root)
{
if(root==NULL)
return 0;
return 1+BinaryTreeSize(root->left)+BinaryTreeSize(root->right);
}
void _preorderTraversal(struct TreeNode* root, int* arr,int*pi) {
if(root==NULL)
return;
arr[(*pi)++]=root->val;
_preorderTraversal(root->left,arr,pi);
_preorderTraversal(root->right,arr,pi);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
*returnSize=BinaryTreeSize(root);
int*returnArr=(int*)malloc(sizeof(int)*(*returnSize));
int i=0;
_preorderTraversal(root,returnArr,&i);
return returnArr;
}
这里要传址调用否则形参是实参的临时拷贝,函数调用完就销毁了
5.二叉树的中序遍历
二叉树的中序遍历
思路设计基本一致
编写代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
typedef struct TreeNode TreeNode;
int BinaryTreeSize(TreeNode*root)
{
if(root==NULL)
return 0;
return 1+BinaryTreeSize(root->left)+BinaryTreeSize(root->right);
}
void __inorderTraversal(struct TreeNode* root, int*arr,int* pi)
{
if(root==NULL)
return;
__inorderTraversal(root->left,arr,pi);
arr[(*pi)++]=root->val;
__inorderTraversal(root->right,arr,pi);
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
*returnSize=BinaryTreeSize(root);
int*returnArr=(int*)malloc(sizeof(int)*(*returnSize));
int i=0;
__inorderTraversal(root,returnArr,&i);
return returnArr;
}
6.二叉树的后序遍历
二叉树的后序遍历
插入代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
typedef struct TreeNode TreeNode;
int BinaryTreeSize(TreeNode*root)
{
if(root==NULL)
return 0;
return 1+BinaryTreeSize(root->left)+BinaryTreeSize(root->right);
}
void __postorderTraversal(struct TreeNode* root, int*arr,int* pi)
{
if(root==NULL)
return;
__postorderTraversal(root->left,arr,pi);
__postorderTraversal(root->right,arr,pi);
arr[(*pi)++]=root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) {
*returnSize=BinaryTreeSize(root);
int*returnArr=(int*)malloc(sizeof(int)*(*returnSize));
int i=0;
__postorderTraversal(root,returnArr,&i);
return returnArr;
}
7.二叉树遍历
思路如题
设计程序
创建字符数组读取字符串(还好这里#代表空格否则根本读不全),前序遍历字符串(感觉读取只能用前序来读),遇到’#'返回NULL,其余直接创建结点插入,中序遍历输出即可
#include <stdio.h>
typedef struct BinaryTreeNode{
char data;
struct BinaryTreeNode*left;
struct BinaryTreeNode*right;
}BTNode;
BTNode*BuyNode(char x)
{
BTNode*NewNode=(BTNode*)malloc(sizeof(BTNode));
NewNode->data=x;
NewNode->left=NewNode->right=NULL;
return NewNode;
}
BTNode* PreoderInsert(char*arr,int*pi)
{
if(arr[*pi]=='#')
{
(*pi)++;
return NULL;
}
BTNode*root=BuyNode(arr[(*pi)++]);
root->left=PreoderInsert(arr,pi);
root->right=PreoderInsert(arr,pi);
return root;
}
void InOder(BTNode*root)
{
if(root==NULL)
return;
InOder(root->left);
printf("%c ",root->data);
InOder(root->right);
}
int main() {
char arr[100];
scanf("%s",arr);
int i=0;
BTNode*root=PreoderInsert(arr,&i);
InOder(root);
return 0;
}
8.TopK问题
TOP-K问题:即求数据结合中前K个最⼤的元素或者最⼩的元素,⼀般情况下数据量都⽐较⼤。
⽐如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。
对于Top-K问题,能想到的最简单直接的⽅式就是排序,但是:如果数据量⾮常⼤,排序就不太可取了(可能数据都不能⼀下⼦全部加载到内存中)。最佳的⽅式就是⽤堆来解决,
基本思路如下:
1)⽤数据集合中前K个元素来建堆
前k个最⼤的元素,则建⼩堆
前k个最⼩的元素,则建⼤堆
2)⽤剩余的N-K个元素依次与堆顶元素来⽐较,不满⾜则替换堆顶元素将剩余N-K个元素依次与堆顶元素⽐完之后,堆中剩余的K个元素就是所求的前K个最⼩或者最⼤的元素
设计程序
进行文件操作以写的形式打开,使用rand函数随机生成十万个数据,将前K个数据建堆,遍历剩余的数据与堆顶比较,若是大于则交换并进行向下调整,注意得到的堆是K个最大的元素或者最小的元素,不是排序好的数组。
编写代码
void CreateNDate()
{
// 造数据
int n = 100000;
srand((unsigned)time(NULL));
FILE* fin = fopen("data.txt", "w");
if (fin == NULL)
{
perror("fopen error");
return;
}
for (int i = 0; i < n; ++i)
{
int x = rand();
fprintf(fin, "%d\n", x);
}
fclose(fin);
}
void TOPk()
{
int k = 0;
printf("请输入k:");
scanf("%d", &k);
FILE* fout = fopen("data.txt", "r");
if (fout == NULL)
{
perror("fopen fail!");
exit(1);
}
int* minHeap = (int*)malloc(k * sizeof(int));
if (minHeap == NULL)
{
perror("malloc fail!");
exit(2);
}
//从文件中读取前K个数据
for (int i = 0; i < k; i++)
{
fscanf(fout, "%d", &minHeap[i]);
}
//建堆---小堆
for (int i = (k - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(minHeap, i, k);
}
int x = 0;
while (fscanf(fout, "%d", &x) != EOF)
{
//读取到的数据跟堆顶的数据进行比较
//比堆顶值大,交换入堆
if (x > minHeap[0])
{
minHeap[0] = x;
AdjustDown(minHeap, 0, k);
}
}
for (int i = 0; i < k; i++)
{
printf("%d ", minHeap[i]);
}
fclose(fout);
}
int main()
{
CreateNDate();
TOPk();
return 0;
}