不能短字符串数组具有大字符串数

Posted

技术标签:

【中文标题】不能短字符串数组具有大字符串数【英文标题】:Cannot short string array having large strings numbers 【发布时间】:2018-09-01 20:52:37 【问题描述】:

我必须对仅包含数字的长字符串(长度可达 100 万个字符)的大型数据集进行排序。 同样将所有字符串视为大正数

如果字符串的长度在 18 以内(因此我可以将其转换为长数进行比较),我已经修改了对于大型数据集(数组大小为 200000)非常有效的合并排序代码。

我还实现了一个理论上应该适用于任何长度的字符串(数字字符串)的逻辑。 但是我的代码中有一些故障,不允许对长(长度> 18)字符串的数组进行排序。 我在下面的代码块中添加了一个大写的注释。

注意:对于所有长度的数据集,代码在几秒钟内成功执行,并给出不太正确输出,如最后所示。

下面是我的代码:

    package algorithms;
    import java.math.BigInteger;
    import java.util.Scanner;
    public class BigSort 

    static void merge(String arr[], int l, int m, int r)
    
        int n1 = m - l + 1;
        int n2 = r - m;

        String L[] = new String [n1];
        String R[] = new String [n2];

        for (int i=0; i<n1; ++i)
            L[i] = arr[l + i];
        for (int j=0; j<n2; ++j)
            R[j] = arr[m + 1+ j];

        int i = 0, j = 0;
        int k = l;

        while (i < n1 && j < n2)   
        if (L[i].length() <= R[j].length())
            if(L[i].length()<=18 && R[j].length() <=18) 
                if(BigInteger.valueOf(Long.parseLong(L[i])).compareTo(BigInteger.valueOf(Long.parseLong(R[j]))) <=0)   
                    //this will convert strings to numbers and compare them.
                    //I have used it just to possibly decrease load of-
                    //comparing each characters for sorting smaller strings.
                    arr[k] = L[i];
                    i++;
                else
                    arr[k] = R[j];
                    j++;
                
            else//THIS ELSE PART IS HAVING SOME PROBLEM.
                //if length of string is greater than 18digits
                //it will compare two string character by character to find 
                //the larger string or if they are equal.
                char[] c1 = L[i].toCharArray();
                char[] c2 = R[j].toCharArray();
                int c1leng= c1.length;
                int c2leng= c2.length;
                //int shorter= c1leng < c2leng ? c1leng : c2leng ;
                if(c1leng==c2leng)
                    for(int p=0; p<c1leng; p++)
                    if(c1[p]==c2[p])
                        if(p == c1leng-1) 
                            arr[k] = L[i];
                            i++;
                            break;
                        
                        continue;
                    else if(c1[p]<c2[p])
                        arr[k] = L[i];
                        i++;
                        break;
                    else if(c1[p]>c2[p])
                        arr[k] = R[j];
                        j++;  
                        break;
                    
                    
                else
                    arr[k] = R[j];
                    j++;     
                
            
        else
            arr[k] = R[j];
            j++;
        
        k++;
        

        while (i < n1)
            arr[k] = L[i];
            i++;
            k++;
        

        while (j < n2)
            arr[k] = R[j];
            j++;
            k++;
        
    


    static void sort(String arr[], int l, int r)
    
        if (l < r)
            int m = (l+r)/2;
            sort(arr, l, m);
            sort(arr , m+1, r);
            merge(arr, l, m, r);
        
    

    static String[] bigSorting(String[] arr) 
        sort(arr, 0, arr.length-1);
        return arr; 
    

    public static void main(String[] args)
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        String[] arr = new String[n];

        for(int arr_i = 0; arr_i < n; arr_i++)
              arr[arr_i] = in.next().trim();
        

        System.out.println("result is:");
        String[] result = bigSorting(arr);
        for (int i = 0; i < result.length; i++) 
            System.out.print(result[i] + (i != result.length - 1 ? "\n" : ""));
        
        in.close();
    

这些是我使用的输入(第一行取字符串数,然后跟随所有要排序的字符串。输出是每行中排序的数字字符串):

input(1) 
10
5454545454
212101225515
51212
5141215
52
521
52145
5
5
5

Output(1)//correct
5
5
5
52
521
51212
52145
5141215
5454545454
212101225515

Input(2)
10
5454545454
212101225515
51212
5141215
52
5465156165164215612616546954512202496421
2121564
216451564561564651564561256065
11
55

Output(2)//incorrect
11
52
55
216451564561564651564561256065
51212
2121564
5465156165164215612616546954512202496421
5141215
5454545454
212101225515

【问题讨论】:

静态 String[] bigSorting(String[] arr) sort(arr, 0, arr.length-1);返回 arr;在返回之前你在哪里更改 arr 值/顺序? @Stultuske 我已经在 bigSorting 函数上面编写的函数中完成了它。抱歉,如果你觉得我在某些时候天真。 我看到你在排序,但我没有看到结果被分配/返回给变量 你试过调试器了吗?你的发现是什么? @MrSmith42 非常感谢。那真的奏效了。我已经使用调试器解决了这个问题。 【参考方案1】:

您可以改用new BigInteger(String)

static void merge(String arr[], int l, int m, int r) 
    int n1 = m - l + 1;
    int n2 = r - m;

    String L[] = new String[n1];
    String R[] = new String[n2];

    for (int i = 0; i < n1; ++i)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; ++j)
        R[j] = arr[m + 1 + j];

    int i = 0, j = 0;
    int k = l;

    while (i < n1 && j < n2) 
        if (L[i].length() <= R[j].length()) 
            if (new BigInteger(L[i]).compareTo(new BigInteger(R[j])) <= 0) 
                //this will convert strings to numbers and compare them.
                arr[k] = L[i];
                i++;
             else 
                arr[k] = R[j];
                j++;
            
         else 
            arr[k] = R[j];
            j++;
        
        k++;
    

    while (i < n1) 
        arr[k] = L[i];
        i++;
        k++;
    

    while (j < n2) 
        arr[k] = R[j];
        j++;
        k++;
    

【讨论】:

此解决方案有效。但是当涉及到具有大字符串的大型数据集时,它没有给出任何结果。 (虽然我写的结果是错误的。)谢谢。! @RDhaval - 那将是另一个问题。我修复的只是比较。【参考方案2】:

也许我遗漏了一些东西,但这应该可以完成工作:

class MyComparator implements Comparator<String>

  @Override
  public int compare(String s1,
                     String s2)
  
    BigInteger i1;
    BigInteger i2;
    i1 = new BigInteger(s1);
    i2 = new BigInteger(s2);
    return (i1.compareTo(i2));
  

 // class MyComparator

String[] my_array;
...

Arrays.sort(my_array, new MyComparator());

【讨论】:

【参考方案3】:

非常感谢大家消除我对 compareTo 方法的误解。

但是在大​​数据集的情况下,compareTo 方法是不可行的(在 CPU 充分利用的情况下花费了太多时间),这也是我实现这个手动排序代码的原因之一。 由于主要问题在此代码中(我想解决并且现在已解决),我现在接受我自己的答案。非常感谢@MrSmith42 和@OldCurmudgeon

           else//THIS ELSE PART IS HAVING SOME PROBLEM.
                //if length of string is greater than 18digits
                //it will compare two string character by character to find 
                //the larger string or if they are equal.
                char[] c1 = L[i].toCharArray();
                char[] c2 = R[j].toCharArray();
                int c1leng= c1.length;
                int c2leng= c2.length;
                //int shorter= c1leng < c2leng ? c1leng : c2leng ;
                if(c1leng==c2leng)
                    for(int p=0; p<c1leng; p++)
                    if(c1[p]==c2[p])
                        if(p == c1leng-1) 
                            arr[k] = L[i];
                            i++;
                            break;
                        
                        continue;
                    else if(c1[p]<c2[p])
                        arr[k] = L[i];
                        i++;
                        break;
                    else if(c1[p]>c2[p])
                        arr[k] = R[j];
                        j++;  
                        break;
                    
                    
                else
                    arr[k] = L[i]; //here was the problem. I was assigning R[j] instead of L[i] which was pushing larger elements alternatively.
                    i++;       
                
            

【讨论】:

以上是关于不能短字符串数组具有大字符串数的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法(C#)入门 --- 串和数组

字符串165. 比较版本号

如何将字符串(字节数组作为字符串)转换为短字符串

与字符串数组关联的数组中的最小数字

GO 数组

将“无符号字符”数组转换为“无符号短”数组的有效方法是啥?