Эффективный способ подсчета количества свопов для вставки сортировать массив целых чисел в порядке возрастания

Учитывая массив значений длины n, существует ли способ подсчета количества свопов, которые будут выполняться сортировкой вставки, чтобы отсортировать этот массив во времени лучше, чем O (n 2)?

Например:

arr[]={2 ,1, 3, 1, 2};  // Answer is 4.

Алгоритм:

for i <- 2 to N

    j <- i

 while j > 1 and a[j] < a[j - 1]

       swap a[j] and a[j - 1]  //I want to count this   swaps?

       j <- j - 1

Ответы

Ответ 1

Если вы хотите подсчитать количество свопов, необходимых для сортировки вставки, вы хотите найти следующий номер: для каждого элемента количество предыдущих элементов в массиве меньше его? Суммой этих значений является общее количество выполненных свопов.

Чтобы найти номер, вы можете использовать дерево статистики заказа, сбалансированное двоичное дерево поиска, которое может эффективно рассказать вам, сколько элементов в дереве меньше, чем некоторый заданный элемент. В частности, дерево статистики orde поддерживает O (log n) вставку, удаление, поиск и количество того, сколько элементов в дереве меньше некоторого значения. Затем вы можете подсчитать, сколько команд будет выполняться следующим образом:

  • Инициализировать новое, пустое дерево статистики заказа.
  • Установить count = 0
  • Для каждого элемента массива в порядке:
    • Добавьте элемент в дерево статистики заказа.
    • Добавить, чтобы подсчитать количество элементов в дереве меньше добавленного значения.
  • Возврат,

Это делает O (n) итерации цикла, который принимает время O (log n), поэтому полная работа выполнена O (n log n), которая быстрее, чем подход грубой силы.


Если вы хотите подсчитать количество свопов в сортировке сортировки, вы можете использовать тот факт, что сортировка вставки будет выполнять только обмен на k-м проходе, если после обработки первых элементов k-1 списка элемент в положении k не является k-м наименьшим элементом. Если вы можете сделать это эффективно, то у нас есть следующий базовый эскиз алгоритма:

  • Установить total = 0
  • Для k = 1 - n:
    • Если элемент с индексом k не является k-м наибольшим элементом:
      • Поменяйте его на k-й наибольший элемент.
      • Сумма приращения
  • Общая сумма возврата

Итак, как мы это эффективно реализуем? Нам нужно эффективно проверить, является ли элемент в данном индексе правильным элементом, а также нужно эффективно находить позицию элемента, который действительно принадлежит данному индексу в противном случае. Для этого начните с создания сбалансированного двоичного дерева поиска, которое отображает каждый элемент в его позицию в исходном массиве. Это занимает время O (n log n). Теперь, когда у вас есть сбалансированное дерево, мы можем увеличить структуру, назначив каждому элементу в дереве позицию в отсортированной последовательности, к которой принадлежит этот элемент. Один из способов сделать это - это дерево статистики заказа, а другое - перебирать дерево с обходным путем, аннотируя каждое значение в дереве с его позицией.

Используя эту структуру, мы можем проверить время O (log n), независимо от того, находится ли элемент в правильном положении, просматривая элемент вверх в дереве (время O (log n)), затем просматривая позицию в отсортированную последовательность, в которой он должен быть, и в какой позиции он находится в данный момент (помните, что мы устанавливаем это при создании дерева). Если это не согласуется с нашей ожидаемой позицией, то оно не в том месте, а в противном случае - в нужном месте. Кроме того, мы можем эффективно моделировать своп двух элементов, просматривая эти два элемента в дереве (общее время O (log n)), а затем заменяя их позиции в O (1).

В результате мы можем реализовать вышеупомянутый алгоритм за время O (n log n) -O (n log n) времени для построения дерева, затем n итераций выполнения O (log n) работают для определения того, для обмена.

Надеюсь, это поможет!

Ответ 2

Число перестановок последовательных элементов, необходимых для их упорядочения в их естественном порядке, равно числу инверсий в данной перестановке.

Таким образом, решение этой проблемы состоит в том, чтобы найти количество инверсий в данном массиве чисел.

Это можно решить в O (n log n), используя сортировку слияния.

На шаге слияния, если вы скопируете элемент из правого массива, увеличьте глобальный счетчик (счетчик инверсий) на количество элементов, оставшихся в левом массиве. Это делается потому, что элемент из правого массива, который только что скопирован, участвует в инверсии со всеми элементами, присутствующими в левом массиве.

Надеюсь, что это поможет

Ответ 3

Я не уверен, но я подозреваю, что найти минимальное число сложно. Если нет ярлыка, вы просто будете искать оптимальные сети сортировки, которые вы сможете найти в ваших любимых поисковых системах (или в Википедии).

Если вы заботитесь только о сложности большого вывода, ответ будет O(n log n), и вы можете получить более конкретные границы (некоторые реальные константы там), если вы посмотрите на анализ некоторых эффективных алгоритмов сортировки на месте как heapsort или smoothsort.

Ответ 4

package insertoinSortAnalysis;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Solution {

    private int[] originalArray;

    public static void main(String[] args) {

        Scanner sc;
        try {
            sc = new Scanner(System.in);

            int TestCases = sc.nextInt();

            for (int i = 0; i < TestCases; i++) {
                int sizeofarray = sc.nextInt();

                Solution s = new Solution();
                s.originalArray = new int[sizeofarray];

                for (int j = 0; j < sizeofarray; j++)
                    s.originalArray[j] = sc.nextInt();

                s.devide(s.originalArray, 0, sizeofarray - 1);
                System.out.println(s.count);
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public int[] devide(int[] originalArray, int low, int high) {
        if (low < high) {
            int mid = (low + high) / 2;
            int[] result1 = devide(originalArray, low, mid);
            int[] result2 = devide(originalArray, mid + 1, high);

            return merge(result1, result2);
        }

        int[] result = { originalArray[low] };
        return result;
    }

    private long count = 0;

    private int[] merge(int[] array1, int[] array2) {

        int lowIndex1 = 0;
        int lowIndex2 = 0;
        int highIndex1 = array1.length - 1;
        int highIndex2 = array2.length - 1;
        int result[] = new int[array1.length + array2.length];
        int i = 0;

        while (lowIndex2 <= highIndex2 && lowIndex1 <= highIndex1) {
            int element = array1[lowIndex1];
            while (lowIndex2 <= highIndex2 && element > array2[lowIndex2]) {
                result[i++] = array2[lowIndex2++];
                count += ((highIndex1 - lowIndex1) + 1);
            }
            result[i++] = element;
            lowIndex1++;
        }

        while (lowIndex2 <= highIndex2 && lowIndex1 > highIndex1) {
            result[i++] = array2[lowIndex2++];
        }

        while (lowIndex1 <= highIndex1 && lowIndex2 > highIndex2) {
            result[i++] = array1[lowIndex1++];
        }

        return result;
    }

}

Ответ 5

Каждый своп в сортировке вставки перемещает два смежных элемента - один вверх на один, один вниз на один - и "исправляет" одно пересечение, делая это. Итак:

  • Аннотировать каждый элемент X с его начальным индексом массива, Xi.

  • Сортировка элементов с использованием стабильной сортировки (вы можете использовать quicksort, если вы обрабатываете аннотацию "начальная позиция" в качестве младшего ключа)

  • Возвратите половину суммы абсолютных разностей между каждым аннотированным исходным положением элемента и его конечной позицией (т.е. просто пропустите аннотации, суммирующие абс (Xi-i)).

Как и большинство других ответов, это O (n) пространство и время O (n * log n). Если бы слияние на месте могло быть изменено для подсчета пересечений, это было бы лучше. Я не уверен, что это возможно.

Ответ 6

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int a[200001];
int te[200001];
unsigned long long merge(int arr[],int temp[],int left,int mid,int right)
{
    int i=left;
    int j=mid;
    int k=left;
    unsigned long long int icount=0;
    while((i<=mid-1) && (j<=right))
    {
        if(arr[i]<=arr[j])
        temp[k++]=arr[i++];
        else
        {
            temp[k++]=arr[j++];
            icount+=(mid-i);
        }
    }
    while(i<=mid-1)
    temp[k++]=arr[i++];
    while(j<=right)
    temp[k++]=arr[j++];
    for(int i=left;i<=right;i++)
    arr[i]=temp[i];
    return icount;
}
unsigned long long int mergesort(int arr[],int temp[],int left,int right)
{
    unsigned long long int i=0;
    if(right>left){
        int mid=(left+right)/2;
        i=mergesort(arr,temp,left,mid);
        i+=mergesort(arr,temp,mid+1,right);
        i+=merge(arr,temp,left,mid+1,right);
    }
    return i;
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        printf("%llu\n",mergesort(a,te,0,n-1));
    }
    return 0;
}