📜  计算数组中的反转|设置2(使用自平衡BST)

📅  最后修改于: 2021-05-24 21:40:38             🧑  作者: Mango

数组的反转计数指示–数组要排序的距离(或距离)。如果已对数组进行排序,则反转计数为0。如果以相反的顺序对数组进行排序,则反转计数为最大。
如果a [i]> a [j]且i 例子:

Input: arr[] = {8, 4, 2, 1}
Output: 6

Explanation: Given array has six inversions:
(8,4), (4,2),(8,2), (8,1), (4,1), (2,1).


Input: arr[] = {3, 1, 2}
Output: 2

Explanation:Given array has two inversions:
(3, 1), (3, 2)      

我们已经讨论了朴素的方法和基于合并排序的方法来计算反演。
上述帖子中解决方案的复杂性分析:
天真的方法的时间复杂度为O(n 2 )
基于合并排序的方法的时间复杂度为O(n Log n)。
在阅读本文之前,请仔细阅读AVL树。
有一种更有效的方法可以解决此问题。
方法:想法是使用自平衡二叉搜索树(如红黑树,AVL树等)并对其进行扩充,以便每个节点还可以跟踪右侧子树中的节点数。因此,每个节点将在其右子树中包含节点数,即大于该数目的节点数。因此可以看出,当存在一对(a,b)时,计数增加,其中a出现在数组中的b之前,而a> b ,因此当数组从头到尾遍历时,将元素添加到AVL树和新插入的节点的右子树中的节点数将增加计数或对数(a,b) ,其中b是当前元素。
算法:

  1. 创建一个AVL树,其属性是每个节点都将包含其子树的大小。
  2. 从头到尾遍历数组。
  3. 对于每个元素,将元素插入AVL树中
  4. 可以通过检查其右子节点的子树的大小来找到大于当前元素的节点数,从而可以确保当前节点的右子树中的元素的索引小于当前元素,并且它们的值大于当前元素。因此,这些元素满足条件。
  5. 因此,通过当前插入节点的右子节点的子树的大小来增加计数。
  6. 显示计数。

执行:

C++
// An AVL Tree based C++ program to count
// inversion in an array
#include
using namespace std;
 
// An AVL tree node
struct Node
{
    int key, height;
    struct Node *left, *right;
 
// size of the tree rooted with this Node
    int size;
};
 
// A utility function to get the height of
// the tree rooted with N
int height(struct Node *N)
{
    if (N == NULL)
        return 0;
    return N->height;
}
 
// A utility function to size of the
// tree of rooted with N
int size(struct Node *N)
{
    if (N == NULL)
        return 0;
    return N->size;
}
 
/* Helper function that allocates a new Node with
the given key and NULL left and right pointers. */
struct Node* newNode(int key)
{
    struct Node* node = new Node;
    node->key   = key;
    node->left   = node->right  = NULL;
    node->height = node->size = 1;
    return(node);
}
 
// A utility function to right rotate
// subtree rooted with y
struct Node *rightRotate(struct Node *y)
{
    struct Node *x = y->left;
    struct Node *T2 = x->right;
 
    // Perform rotation
    x->right = y;
    y->left = T2;
 
    // Update heights
    y->height = max(height(y->left),
 height(y->right))+1;
    x->height = max(height(x->left),
 height(x->right))+1;
 
    // Update sizes
    y->size = size(y->left) + size(y->right) + 1;
    x->size = size(x->left) + size(x->right) + 1;
 
    // Return new root
    return x;
}
 
// A utility function to left rotate
// subtree rooted with x
struct Node *leftRotate(struct Node *x)
{
    struct Node *y = x->right;
    struct Node *T2 = y->left;
 
    // Perform rotation
    y->left = x;
    x->right = T2;
 
    //  Update heights
    x->height = max(height(x->left), height(x->right))+1;
    y->height = max(height(y->left), height(y->right))+1;
 
    // Update sizes
    x->size = size(x->left) + size(x->right) + 1;
    y->size = size(y->left) + size(y->right) + 1;
 
    // Return new root
    return y;
}
 
// Get Balance factor of Node N
int getBalance(struct Node *N)
{
    if (N == NULL)
        return 0;
    return height(N->left) - height(N->right);
}
 
// Inserts a new key to the tree rotted with Node. Also, updates
// *result (inversion count)
struct Node* insert(struct Node* node, int key, int *result)
{
    /* 1.  Perform the normal BST rotation */
    if (node == NULL)
        return(newNode(key));
 
    if (key < node->key)
    {
        node->left  = insert(node->left, key, result);
 
        // UPDATE COUNT OF GREATE ELEMENTS FOR KEY
        *result = *result + size(node->right) + 1;
    }
    else
        node->right = insert(node->right, key, result);
 
    /* 2. Update height and size of this ancestor node */
    node->height = max(height(node->left),
                       height(node->right)) + 1;
    node->size = size(node->left) + size(node->right) + 1;
 
    /* 3. Get the balance factor of this ancestor node to
          check whether this node became unbalanced */
    int balance = getBalance(node);
 
    // If this node becomes unbalanced, then there are
    // 4 cases
 
    // Left Left Case
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);
 
    // Right Right Case
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);
 
    // Left Right Case
    if (balance > 1 && key > node->left->key)
    {
        node->left =  leftRotate(node->left);
        return rightRotate(node);
    }
 
    // Right Left Case
    if (balance < -1 && key < node->right->key)
    {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }
 
    /* return the (unchanged) node pointer */
    return node;
}
 
// The following function returns inversion count in arr[]
int getInvCount(int arr[], int n)
{
  struct Node *root = NULL;  // Create empty AVL Tree
 
  int result = 0;   // Initialize result
 
  // Starting from first element, insert all elements one by
  // one in an AVL tree.
  for (int i=0; i


Java
// AVL Tree based Java program to count
// inversion in an array
import java.util.*;
 
class GfG{
 
// Initialize result
static int result = 0;
 
// An AVL tree node
static class Node
{
    int key, height;
    Node left, right;
 
    // Size of the tree rooted
    // with this Node
    int size;
}
 
// A utility function to get the height of
// the tree rooted with N
static int height(Node N)
{
    if (N == null)
        return 0;
         
    return N.height;
}
 
// A utility function to size of the
// tree of rooted with N
static int size(Node N)
{
    if (N == null)
        return 0;
         
    return N.size;
}
 
// A utility function to create a new node
static Node newNode(int ele)
{
    Node temp = new Node();
    temp.key = ele;
    temp.left = null;
    temp.right = null;
    temp.height = 1;
    temp.size = 1;
    return temp;
}
 
// A utility function to right rotate
// subtree rooted with y
static Node rightRotate(Node y)
{
    Node x = y.left;
    Node T2 = x.right;
 
    // Perform rotation
    x.right = y;
    y.left = T2;
 
    // Update heights
    y.height = Math.max(height(y.left),
                        height(y.right)) + 1;
    x.height = Math.max(height(x.left),
                        height(x.right)) + 1;
 
    // Update sizes
    y.size = size(y.left) + size(y.right) + 1;
    x.size = size(x.left) + size(x.right) + 1;
 
    // Return new root
    return x;
}
 
// A utility function to left rotate
// subtree rooted with x
static Node leftRotate(Node x)
{
    Node y = x.right;
    Node T2 = y.left;
 
    // Perform rotation
    y.left = x;
    x.right = T2;
 
    // Update heights
    x.height = Math.max(height(x.left),
                        height(x.right)) + 1;
    y.height = Math.max(height(y.left),
                        height(y.right)) + 1;
 
    // Update sizes
    x.size = size(x.left) + size(x.right) + 1;
    y.size = size(y.left) + size(y.right) + 1;
 
    // Return new root
    return y;
}
 
// Get Balance factor of Node N
static int getBalance(Node N)
{
    if (N == null)
        return 0;
         
    return height(N.left) - height(N.right);
}
 
// Inserts a new key to the tree rotted
// with Node. Also, updates *result
// (inversion count)
static Node insert(Node node, int key)
{
     
    // 1. Perform the normal BST rotation
    if (node == null)
        return (newNode(key));
 
    if (key < node.key)
    {
        node.left = insert(node.left, key);
 
        // UPDATE COUNT OF GREATE ELEMENTS FOR KEY
        result = result + size(node.right) + 1;
    }
    else
        node.right = insert(node.right, key);
 
    // 2. Update height and size of
    // this ancestor node
    node.height = Math.max(height(node.left),
                           height(node.right)) + 1;
    node.size = size(node.left) +
                size(node.right) + 1;
 
    // 3. Get the balance factor of this
    // ancestor node to check whether this
    // node became unbalanced
    int balance = getBalance(node);
 
    // If this node becomes unbalanced,
    // then there are 4 cases
 
    // Left Left Case
    if (balance > 1 && key < node.left.key)
        return rightRotate(node);
 
    // Right Right Case
    if (balance < -1 && key > node.right.key)
        return leftRotate(node);
 
    // Left Right Case
    if (balance > 1 && key > node.left.key)
    {
        node.left = leftRotate(node.left);
        return rightRotate(node);
    }
 
    // Right Left Case
    if (balance < -1 && key < node.right.key)
    {
        node.right = rightRotate(node.right);
        return leftRotate(node);
    }
 
    // Return the (unchanged) node pointer
    return node;
}
 
// The following function returns inversion
// count in arr[]
static void getInvCount(int arr[], int n)
{
     
    // Create empty AVL Tree
    Node root = null;
 
    // Starting from first element,
    // insert all elements one by
    // one in an AVL tree.
    for(int i = 0; i < n; i++)
 
        // Note that address of result
        // is passed as insert operation
        // updates result by adding count
        // of elements greater than arr[i]
        // on left of arr[i]
        root = insert(root, arr[i]);
}
 
// Driver code
public static void main(String[] args)
{
    int[] arr = new int[] { 8, 4, 2, 1 };
    int n = arr.length;
    getInvCount(arr, n);
     
    System.out.print("Number of inversions " +
                     "count are : " + result);
}
}
 
// This code is contributed by tushar_bansal


Python3
# An AVL Tree based Python program to
# count inversion in an array
 
# A utility function to get height of
# the tree rooted with N
def height(N):
    if N == None:
        return 0
    return N.height
 
# A utility function to size of the
# tree of rooted with N
def size(N):
    if N == None:
        return 0
    return N.size
 
# Helper function that allocates a new
# Node with the given key and NULL left
# and right pointers.
class newNode:
    def __init__(self, key):
        self.key = key
        self.left = self.right = None
        self.height = self.size = 1
 
# A utility function to right rotate
# subtree rooted with y
def rightRotate(y):
    x = y.left
    T2 = x.right
 
    # Perform rotation
    x.right = y
    y.left = T2
 
    # Update heights
    y.height = max(height(y.left),
                   height(y.right)) + 1
    x.height = max(height(x.left),
                   height(x.right)) + 1
 
    # Update sizes
    y.size = size(y.left) + size(y.right) + 1
    x.size = size(x.left) + size(x.right) + 1
 
    # Return new root
    return x
 
# A utility function to left rotate
# subtree rooted with x
def leftRotate(x):
    y = x.right
    T2 = y.left
 
    # Perform rotation
    y.left = x
    x.right = T2
 
    # Update heights
    x.height = max(height(x.left),
                   height(x.right)) + 1
    y.height = max(height(y.left),
                   height(y.right)) + 1
 
    # Update sizes
    x.size = size(x.left) + size(x.right) + 1
    y.size = size(y.left) + size(y.right) + 1
 
    # Return new root
    return y
 
# Get Balance factor of Node N
def getBalance(N):
    if N == None:
        return 0
    return height(N.left) - height(N.right)
 
# Inserts a new key to the tree rotted
# with Node. Also, updates *result (inversion count)
def insert(node, key, result):
     
    # 1. Perform the normal BST rotation
    if node == None:
        return newNode(key)
 
    if key < node.key:
        node.left = insert(node.left, key, result)
 
        # UPDATE COUNT OF GREATE ELEMENTS FOR KEY
        result[0] = result[0] + size(node.right) + 1
    else:
        node.right = insert(node.right, key, result)
 
    # 2. Update height and size of this ancestor node
    node.height = max(height(node.left),   
                      height(node.right)) + 1
    node.size = size(node.left) + size(node.right) + 1
 
    # 3. Get the balance factor of this ancestor
    #     node to check whether this node became
    #    unbalanced
    balance = getBalance(node)
 
    # If this node becomes unbalanced, 
    # then there are 4 cases
 
    # Left Left Case
    if (balance > 1 and key < node.left.key):
        return rightRotate(node)
 
    # Right Right Case
    if (balance < -1 and key > node.right.key):
        return leftRotate(node)
 
    # Left Right Case
    if balance > 1 and key > node.left.key:
        node.left = leftRotate(node.left)
        return rightRotate(node)
 
    # Right Left Case
    if balance < -1 and key < node.right.key:
        node.right = rightRotate(node.right)
        return leftRotate(node)
 
    # return the (unchanged) node pointer
    return node
 
# The following function returns
# inversion count in arr[]
def getInvCount(arr, n):
    root = None # Create empty AVL Tree
 
    result = [0] # Initialize result
 
    # Starting from first element, insert all
    # elements one by one in an AVL tree.
    for i in range(n):
 
        # Note that address of result is passed
        # as insert operation updates result by
        # adding count of elements greater than
        # arr[i] on left of arr[i]
        root = insert(root, arr[i], result)
 
    return result[0]
 
# Driver Code
if __name__ == '__main__':
    arr = [8, 4, 2, 1]
    n = len(arr)
    print("Number of inversions count are :",
                         getInvCount(arr, n))
 
# This code is contributed by PranchalK


C#
// AVL Tree based C# program to count
// inversion in an array
using System;
class GfG
{
 
  // Initialize result
  static int result = 0;
 
  // An AVL tree node
  public
    class Node
    {
      public
        int key, height;
      public
        Node left, right;
 
      // Size of the tree rooted
      // with this Node
      public
        int size;
    }
 
  // A utility function to get the height of
  // the tree rooted with N
  static int height(Node N)
  {
    if (N == null)
      return 0; 
    return N.height;
  }
 
  // A utility function to size of the
  // tree of rooted with N
  static int size(Node N)
  {
    if (N == null)
      return 0;      
    return N.size;
  }
 
  // A utility function to create a new node
  static Node newNode(int ele)
  {
    Node temp = new Node();
    temp.key = ele;
    temp.left = null;
    temp.right = null;
    temp.height = 1;
    temp.size = 1;
    return temp;
  }
 
  // A utility function to right rotate
  // subtree rooted with y
  static Node rightRotate(Node y)
  {
    Node x = y.left;
    Node T2 = x.right;
 
    // Perform rotation
    x.right = y;
    y.left = T2;
 
    // Update heights
    y.height = Math.Max(height(y.left),
                        height(y.right)) + 1;
    x.height = Math.Max(height(x.left),
                        height(x.right)) + 1;
 
    // Update sizes
    y.size = size(y.left) + size(y.right) + 1;
    x.size = size(x.left) + size(x.right) + 1;
 
    // Return new root
    return x;
  }
 
  // A utility function to left rotate
  // subtree rooted with x
  static Node leftRotate(Node x)
  {
    Node y = x.right;
    Node T2 = y.left;
 
    // Perform rotation
    y.left = x;
    x.right = T2;
 
    // Update heights
    x.height = Math.Max(height(x.left),
                        height(x.right)) + 1;
    y.height = Math.Max(height(y.left),
                        height(y.right)) + 1;
 
    // Update sizes
    x.size = size(x.left) + size(x.right) + 1;
    y.size = size(y.left) + size(y.right) + 1;
 
    // Return new root
    return y;
  }
 
  // Get Balance factor of Node N
  static int getBalance(Node N)
  {
    if (N == null)
      return 0;    
    return height(N.left) - height(N.right);
  }
 
  // Inserts a new key to the tree rotted
  // with Node. Also, updates *result
  // (inversion count)
  static Node insert(Node node, int key)
  {
 
    // 1. Perform the normal BST rotation
    if (node == null)
      return (newNode(key));
    if (key < node.key)
    {
      node.left = insert(node.left, key);
 
      // UPDATE COUNT OF GREATE ELEMENTS FOR KEY
      result = result + size(node.right) + 1;
    }
    else
      node.right = insert(node.right, key);
 
    // 2. Update height and size of
    // this ancestor node
    node.height = Math.Max(height(node.left),
                           height(node.right)) + 1;
    node.size = size(node.left) +
      size(node.right) + 1;
 
    // 3. Get the balance factor of this
    // ancestor node to check whether this
    // node became unbalanced
    int balance = getBalance(node);
 
    // If this node becomes unbalanced,
    // then there are 4 cases
 
    // Left Left Case
    if (balance > 1 && key < node.left.key)
      return rightRotate(node);
 
    // Right Right Case
    if (balance < -1 && key > node.right.key)
      return leftRotate(node);
 
    // Left Right Case
    if (balance > 1 && key > node.left.key)
    {
      node.left = leftRotate(node.left);
      return rightRotate(node);
    }
 
    // Right Left Case
    if (balance < -1 && key < node.right.key)
    {
      node.right = rightRotate(node.right);
      return leftRotate(node);
    }
 
    // Return the (unchanged) node pointer
    return node;
  }
 
  // The following function returns inversion
  // count in []arr
  static void getInvCount(int []arr, int n)
  {
 
    // Create empty AVL Tree
    Node root = null;
 
    // Starting from first element,
    // insert all elements one by
    // one in an AVL tree.
    for(int i = 0; i < n; i++)
 
      // Note that address of result
      // is passed as insert operation
      // updates result by adding count
      // of elements greater than arr[i]
      // on left of arr[i]
      root = insert(root, arr[i]);
  }
 
  // Driver code
  public static void Main(String[] args)
  {
    int[] arr = new int[] { 8, 4, 2, 1 };
    int n = arr.Length;
    getInvCount(arr, n);
 
    Console.Write("Number of inversions " +
                  "count are : " + result);
  }
}
 
// This code is contributed by gauravrajput1


输出:

Number of inversions count are: 6

复杂度分析:

  • 时间复杂度: O(n Log n)。
    在AVL插入中插入会花费O(log n)时间,并且在树中插入了n个元素,因此时间复杂度为O(n log n)。
  • 空间复杂度: O(n)。
    要创建最大n个节点O(n)的AVL树,需要额外的空间。