Сортировка по основанию неправильно сортирует массив строк, когда они имеют разную длину

Итак, в настоящее время я пытаюсь отсортировать заданный массив строк в Java. Я использую сортировку по основанию, чтобы сохранить временную сложность на уровне O (N + K). N — длина массива, а k — длина всех символов. Мое намерение состояло в том, чтобы алгоритм сортировки сначала сортировал числа в числовом порядке, а затем в алфавитном порядке с любыми буквами. Таким образом, если бы входной массив был {"cd", "12", "ab"}, результат сортировки выглядел бы как {"12", "ab", "cd"}. Моя проблема связана с обработкой строк разной длины. Чтобы компенсировать разную длину, я предварительно обработал данные, добавив пробелы в конец каждой строки, чтобы сделать все строки одинаковой длины. Однако в фактическом процессе сортировки это приводит к неправильному порядку строк. Я занимался отладкой и знаю проблему, связанную с алгоритмом сортировки, обрабатывающим искусственные пробелы. Я использую хеш-карту, чтобы определить приоритет всех символов, когда дело доходит до фактической сортировки. Не уверен, как это исправить. Я проверил его на массиве строк одинаковой длины, и он правильно сортируется. Таким образом, проблема определенно связана с обработкой пробелов. Как это исправить?

import java.util.HashMap;
public class StringSort {

    public static void main(String[] args) {
        String[] arr = {"apple", "beans", "cool5407", "algorithm", "number", "2021", "cs"};
        //String[] arr = {"34", "45", "23", "67","12", "ab", "56"};
        System.out.print("Initial Array: ");
        print(arr);
        radixSort(arr);
        
    }
    
    static void radixSort(String[] arr)
    {       
        /*If initial list has nothing in it, then ignore it.
         * If initial list has only 1 item in it, then its already sorted.
         * If it has more than 1 item, then sorting may be required. */      
        if(arr.length > 1)
        {
                        
            //Find Longest String
            int maxLength = 0;
            for(int i = 0; i < arr.length; i++)
            {
                if(arr[i].length() > maxLength)
                    maxLength = arr[i].length();
                
            }
            
            System.out.println("Max Length : " + maxLength);
            
            //Process Strings to make them all same length
            for(int STRIndex = 0; STRIndex < arr.length; STRIndex++)
            {
                if(arr[STRIndex].length() < maxLength)
                {
                    while(arr[STRIndex].length() < maxLength)
                    {
                        arr[STRIndex] = arr[STRIndex] + " ";
                    }
                    System.out.println("Remade String: [" + arr[STRIndex] + "] " + "Length: " + arr[STRIndex].length());
                }
                
            }
            
            //Sort by letter column via iterating
            for(int column = 0; column < maxLength; column++)
            {
                System.out.println("Sotring Column: " + column);
                countingSort(arr, column);
            }
            
            //Print Final Result
            System.out.print("Final Result: ");
            print(arr);
            
        }
    }// End of Radix Sort
    
    static void countingSort(String[] arr, int letterColumn)
    {
        int NUM_CHARACTERS = 37; //Number of Unique Characters that can be found in strings
        
        //Create Map to Map Letters to Numbers
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        //Map Numbers to Values (Higher Numbers belong in front)
        map.put(' ', 0); map.put('0',1); map.put('1',2); map.put('2',3); map.put('3',4); map.put('4',5); map.put('5',6); map.put('6',7); 
        map.put('7',8); map.put('8',9); map.put('9',10);
        //Map Letters to Values (Higher Numbers belong in front)
        map.put('a',11); map.put('b',12); map.put('c',13);  map.put('d',14); map.put('e',15); map.put('f',16); map.put('g',17); 
        map.put('h',18); map.put('i',19); map.put('j',20); map.put('k',21); map.put('l',22); map.put('m',23); map.put('n',24);
        map.put('o',25); map.put('p',26); map.put('q',27); map.put('r',28); map.put('s',29); map.put('t',30); map.put('u',31); 
        map.put('v',32);map.put('w',33); map.put('x',34); map.put('y',35); map.put('z',36); 
        
        String[] result = new String[arr.length];
        int[] count = new int[NUM_CHARACTERS];
        
        print(arr);
        
        
        //Store number of instances of each letter/number in a given column for each string
        for(int index = 0; index < arr.length; index++)
        {
            String currentString = arr[index];//Get Current String          
            int currentChar = map.get(currentString.charAt(letterColumn)); //Get int value of the Current Character
            count[currentChar]++; //Count the instance
            
        }
        
        //Edit count[index] so it contains position of digit in result
        for(int index = 1; index < NUM_CHARACTERS; index++)
        {
            count[index] += count[index-1];
        }
        
        //Create Result
        for(int index = arr.length - 1; index >= 0; index--)
        {
            String currentString = arr[index]; //Get Current String 
            int currentChar = map.get(arr[index].charAt(letterColumn)); //Get int value of the Current Character
            
            result[count[currentChar]-1] = arr[index]; //Set Character in Result to be sorted element
            count[currentChar]--;//Subtract from the current character count
            
        }
        
        //Override original arr[] to that it contains new array
        for(int index = 0; index < arr.length; index++)
        {
            arr[index] = result[index];
        }
        
    }//End of Counting Sort
    
    
    static void print(String[] arr)
    {
        System.out.print("[");
        //Print Final Result
        for(int index = 0; index < arr.length; index++)
        {
            System.out.print(arr[index] + ", ");
        }
        System.out.print("]");
        System.out.println();
    }
    
}
    

person mr pk    schedule 12.02.2021    source источник
comment
Каков твой вопрос?   -  person Maruthi Adithya    schedule 12.02.2021
comment
Как мне это исправить   -  person mr pk    schedule 12.02.2021
comment
Возможно, я рассмотрю это более подробно позже, но скажу, что я реализовал сортировку по основанию на C++, и мне вообще не нужно было заполнять строки. Прошло около полутора лет, поэтому я не разбираюсь в деталях, но, вероятно, есть более фундаментальная проблема с вашим алгоритмом, если вам нужно добавить пробелы.   -  person Layne Bernardo    schedule 12.02.2021
comment
@mrpk, вам нужно считать сортировку по обратным индексам. я добавил рабочий код в соответствии с вашим подходом к добавлению пробелов в конце.   -  person Thiyanesh    schedule 12.02.2021


Ответы (1)


вопросы

Текущий код не будет работать и для ввода одинаковой длины.

String[] arr = {"11", "20"};

Причина

            //Sort by letter column via iterating
            for(int column = 0; column < maxLength; column++)
  1. Текущий код перемещается от первого (слева) к последнему (справа)
  2. Это приведет к окончательной сортировке текущего кода на основе последнего индекса (и, следовательно, перезапишет сделанные изменения).

Предложения

  1. На каждой итерации сортировки подсчетом индекс должен перемещаться от последнего (справа) к первому (слева). Приведенный выше код следует изменить на
//Sort by letter column via iterating in reverse order
for (int column = maxLength - 1; column >= 0; column--)
  1. Или, если требуется двигаться слева направо, создайте подсегменты на основе уже отсортированных и рекурсивно отсортируйте эти подсегменты. (никогда не меняйте порядок начальных символов)

Рабочий упрощенный код

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class StringSort {

    private final Map<Character, Integer> order;
    private final int charCount;

    public StringSort() {
        String characters = " 0123456789abcdefghijklmnopqrstuvwxyz";
        order = Collections.unmodifiableMap(IntStream.range(0, characters.length()).boxed()
            .collect(Collectors.toMap(characters::charAt, Function.identity())));
        charCount = characters.length();
    }

    public static void main(String[] args) {
        String[] arr = {"apple", "beans", "cool5407", "algorithm", "number", "2021", "cs"};
        StringSort stringSort = new StringSort();
        stringSort.radixSort(arr);
    }

    static void print(String prefix, String[] input) {
        System.out.println(prefix + Arrays.deepToString(input));
    }

    void radixSort(String[] input) {
        print("Initial Array: ", input);

        if (input.length < 2) {
            return;
        }

        int maxLength = Arrays.stream(input).map(s -> s.length())
            .max(Comparator.comparingInt(Integer::intValue)).get();
        System.out.println("Max Length : " + maxLength);

        input = Arrays.stream(input)
            .map(s -> s + new String(new char[maxLength - s.length()])
                .replace("\0", " "))
            .toArray(String[]::new); // repeat " "
        print("Filled Array: ", input);

        //Sort by letter column via iterating
        for (int column = maxLength - 1; column >= 0; column--) {
            System.out.println("Sotring by column: " + column);
            countingSort(input, column);
            print("Updated State: ",  input);
        }
        print("Final Result: ", input);
    }

    void countingSort(String[] input, final int letterColumn) {
        final int stringCount = input.length;
        String[] result = new String[input.length];
        int[] counter = new int[charCount];

        Arrays.stream(input).map(s -> order.get(s.charAt(letterColumn))).forEach(c -> counter[c]++);

        IntStream.range(1, order.size()).forEach(i -> counter[i] += counter[i - 1]);

        for (int index = stringCount - 1; index >= 0; index--) {
            int currentChar = order.get(input[index].charAt(letterColumn));
            result[counter[currentChar] - 1] = input[index];
            --counter[currentChar];
        }

        IntStream.range(0, stringCount).forEach(i -> input[i] = result[i]);
    }
}
person Thiyanesh    schedule 12.02.2021
comment
Спасибо! Вы были правы, это потому, что я выполнял сортировку, начиная с первого столбца, а не начиная с последнего. - person mr pk; 12.02.2021
comment
Спасибо также за помощь в обновлении информации о сортировке counting и radix в Java. - person Thiyanesh; 12.02.2021