数据结构---二叉查找数与堆

文章目录

    • 一、二叉树
        • 1.1 实现一个二叉查找树,并且支持插入、删除、查找操作
        • 1.2 实现查找二叉查找树中某个节点的后继、前驱节点
        • 1.3 实现二叉树前、中、后序以及按层遍历
    • 二、堆
        • 2.1 小顶堆、大顶堆、优先级队列
        • 2.2 实现堆排序
    • 三、对应的 LeetCode 练习题
        • 3.1 Invert Binary Tree(翻转二叉树)
        • 3.2 Maximum Depth of Binary Tree(二叉树的最大深度)
        • 3.3 Validate Binary Search Tree(验证二叉查找树)
        • 3.4 Path Sum(路径总和)

一、二叉树

1.1 实现一个二叉查找树,并且支持插入、删除、查找操作

二叉查找数:
二叉查找树(Binary Search Tree),又被称为二叉搜索树。
它是特殊的二叉树:对于二叉树,假设x为二叉树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。那么,这棵树就是二叉查找树。

//节点定义
typedef struct BSTreeNode{
    int data;                     
    struct BSTreeNode *left;
    struct BSTreeNode *right;
    struct BSTreeNode *parent;
}Node,*BSTree;
 

//插入
BSTree* insertTree(BSTree *t,int data)
{
    if(t==NULL)
    {
        t=(BSTree *)malloc(sizeof(BSTree));
        t->data=data;
        t->right=NULL;
        t->left=NULL;
        return t;
    }
    if(t->data>data)
    {
        t->left=insertTree(t->left,data);
    }
    else if(t->data < data)
    {
        t->right=insertTree(t->right,data);
    }
    else{
        printf("%d已经在树中!\n",data);
    }
}

//删除
BSTree* deleteTree(BSTree *T,int data)
{
    if(T==NULL)
    {
        return T;
    }
    if(T->data>data){
        T->left=deleteTree(T->left,data);
    }
    else if(T->dataright=deleteTree(T->right,data);
    }
    else if(T->left != NULL && T->right != NULL)
    {
        T->data=findMin(T->right)->data;
        T->right=deleteTree(T->right,data);
    }
    else
    {
        T=(T->left != NULL)?T->left:T->right;
    }
    return T;
}

//查找
BSTree* search(BSTree *T,int data)
{
    if(T==NULL)
    {
        printf("Tree is NUll\n");
    }
    else if(T->data>data)
    {
        return search(T->left,data);
    }
    else if(T->dataright,data);
    }
    else 
    {
        return T;
    }
}

1.2 实现查找二叉查找树中某个节点的后继、前驱节点

//节点的前驱是该节点的左子树的最大节点
//节点的后继是该节点的右子树中的最小节点

Node* bstree_predecessor(Node *x)
{
    // 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
    if (x->left != NULL)
        return bstree_maximum(x->left);

    // 如果x没有左孩子。则x有以下两种可能:
    // 1. 若x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
    // 2. x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。
    Node* y = x->parent;
    while ((y!=NULL) && (x==y->left))
    {
        x = y;
        y = y->parent;
    }

    return y;
}

Node* bstree_successor(Node *x)
{
    // 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
    if (x->right != NULL)
        return bstree_minimum(x->right);

    // 如果x没有右孩子。则x有以下两种可能:
    // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
    // (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。
    Node* y = x->parent;
    while ((y!=NULL) && (x==y->right))
    {
        x = y;
        y = y->parent;
    }

    return y;
}

1.3 实现二叉树前、中、后序以及按层遍历

//前序遍历 递归实现
void preorder(BSTree tree){
    if(tree != NULL){
        printf("%d ",tree->key);
        preorder(tree->left);
        preorder(tree->right);
    }
}

//中序遍历
void inorder(BSTree tree){
    if(tree != NULL){
        inorder(tree->left);
        printf("%d ",tree->key);
        inorder(tree->right);
    }
}

//后序遍历
void postorder(BSTree tree){
    if(tree != NULL){
        postorder(tree->left);
        postorder(tree->right);
        printf("%d ",tree->key);
    }
}

二、堆

2.1 小顶堆、大顶堆、优先级队列

堆:堆实际上是一棵完全二叉树,任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。分为大顶堆和小顶堆。

大顶堆:所有节点的子节点比其自身小的堆。Key[i]>=Key[2i+1]&&key>=key[2i+2]

小顶堆:所有节点的子节点比其自身大的堆。Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]

优先级队列:优先级队列是带有优先级的队列,普通的队列是从队尾进数据,从队头出数据,而优先级队列入数据一样,不过出数据的时候是根据数据的优先级从高到低进行出数据,这种数据类型适用于一些文件管理的软件,优先级队列的使用也会加快工作效率,相比于一般队列,优先级队列也不会出现假溢出的问题。

// 初始化大顶堆
void initHeapMax(int a[], int len) {
 // 从完全二叉树最后一个非子节点开始
 // 在数组中第一个元素的索引是0
 // 第n个元素的左孩子为2n+1,右孩子为2n+2,
 // 最后一个非子节点位置在(n - 1) / 2
 for (int i = (len - 1) / 2; i >= 0; --i) {
  adjustMaxHeap(a, len, i);
 }
}
  
//调整大顶堆
void adjustMaxHeap(int a[], int len, int parentNodeIndex) {
 // 若只有一个元素,那么只能是堆顶元素,也没有必要再排序了
 if (len <= 1) {
  return;
 }
  
 // 记录比父节点大的左孩子或者右孩子的索引
 int targetIndex = -1;
  
 // 获取左、右孩子的索引
 int leftChildIndex = 2 * parentNodeIndex + 1;
 int rightChildIndex = 2 * parentNodeIndex + 2;
  
 // 没有左孩子
 if (leftChildIndex >= len) {
  return;
 }
  
 // 有左孩子,但是没有右孩子
 if (rightChildIndex >= len) {
  targetIndex = leftChildIndex;
 }
 // 有左孩子和右孩子
 else {
  // 取左、右孩子两者中最大的一个
  targetIndex = a[leftChildIndex] > a[rightChildIndex] ? leftChildIndex : rightChildIndex;
 }
  
 // 只有孩子比父节点的值还要大,才需要交换
 if (a[targetIndex] > a[parentNodeIndex]) {
  int temp = a[targetIndex];
   
  a[targetIndex] = a[parentNodeIndex];
  a[parentNodeIndex] = temp;
   
   
  // 交换完成后,有可能会导致a[targetIndex]结点所形成的子树不满足堆的条件,
  // 若不满足堆的条件,则调整之使之也成为堆
  adjustMaxHeap(a, len, targetIndex);
 }
}

//小顶堆初始化
void initHeapMin(int a[], int len) {
 for (int i = (len - 1) / 2; i >= 0; --i) {
  adjustMinHeap(a, len, i);
 }
}
  
void adjustMinHeap(int a[], int len, int parentNodeIndex) {
 // 若只有一个元素,那么只能是堆顶元素,也没有必要再排序了
 if (len <= 1) {
  return;
 }
  
 // 记录比父节点大的左孩子或者右孩子的索引
 int targetIndex = -1;
  
 // 获取左、右孩子的索引
 int leftChildIndex = 2 * parentNodeIndex + 1;
 int rightChildIndex = 2 * parentNodeIndex + 2;
  
 // 没有左孩子
 if (leftChildIndex >= len) {
  return;
 }
  
 // 有左孩子,但是没有右孩子
 if (rightChildIndex >= len) {
  targetIndex = leftChildIndex;
 }
 // 有左孩子和右孩子
 else {
  // 取左、右孩子两者中最上的一个
  targetIndex = a[leftChildIndex] < a[rightChildIndex] ? leftChildIndex : rightChildIndex;
 }
  
 // 只有孩子比父节点的值还要小,才需要交换
 if (a[targetIndex] < a[parentNodeIndex]) {
  int temp = a[targetIndex];
   
  a[targetIndex] = a[parentNodeIndex];
  a[parentNodeIndex] = temp;
   
   
  // 交换完成后,有可能会导致a[targetIndex]结点所形成的子树不满足堆的条件,
  // 若不满足堆的条件,则调整之使之也成为堆
  adjustMinHeap(a, len, targetIndex);
 }
}

2.2 实现堆排序

//用大顶堆实现
void heapSort(int a[], int len) {
        if (len <= 1) {
            return;
         }
  
 // 初始堆成无序最大堆
 initHeapMax(a, len);
  
 for (int i = len - 1; i > 0; --i) {
  // 将当前堆顶元素与最后一个元素交换,保证这一趟所查找到的堆顶元素与最后一个元素交换
  if (a[0] > a[i]) {
   int temp = a[0];
   a[0] = a[i];
   a[i] = temp;
  }
   
  adjustMaxHeap(a, i - 1, 0);
 }
}

三、对应的 LeetCode 练习题

3.1 Invert Binary Tree(翻转二叉树)

LeetCode 226

//递归  交换根节点的左右子树,对左右子树分别执行递归反转

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == NULL)
            return NULL;
        TreeNode *pNode=root->left;
        root->left=invertTree(root->right);
        root->right=invertTree(pNode);
        return root;
        
    }
};

3.2 Maximum Depth of Binary Tree(二叉树的最大深度)

leetcode 104

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int maxDepth(TreeNode* root) {
        int l,r,m;
        if(root != NULL)
        {
            l=maxDepth(root->left);
            r=maxDepth(root->right);
            m=max(l,r);
            return m+1;
        }
        else 
            return 0;
    }
};

3.3 Validate Binary Search Tree(验证二叉查找树)

LeetCode 98

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        return isValidBST(root,LONG_MIN,LONG_MAX);
    }
    bool isValidBST(TreeNode *root,long min,long max){
        if(!=root) return true;
        if(root->val <= min || root->val >= max) return false;
        return isValidBST(root->left,min,root->val) && isValidBST(root->right,root->val,max);
    }
};

3.4 Path Sum(路径总和)

LeetCode 112

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if(root == NULL)
            return false;
        if(root -> left == NULL && root->right == NULL && root->val==sum)
            retrun true;
        return hasPathSum(root->left,sum-root->val) || hasPathSum(root->right,sum-root->val);
    }
};

The end~

你可能感兴趣的:(C++,数据结构)