簡體   English   中英

Java通過特定值存儲int矩陣中的值的更好方法

[英]Java better way to store values from matrix of int by specific values

我有一個int [] []矩陣,我想根據它在矩陣中的值將坐標存儲在不同的數組中。 我認為我的解決方案有效,但是效果不是很好...

    public ArrayList<ArrayList<Coords>> storeValues(int[][] labels) {
    int max = getMaxValue(labels);
    ArrayList<ArrayList<Coords>> collection = new ArrayList<ArrayList<Coords>>();
    ArrayList<Coords> coords;

    while (max > 0) {
        coords = new ArrayList<Coords>();
        for (int x = 0; x < labels.length; x++) {
            for (int y = 0; y < labels[0].length; y++) {
                if (max == labels[x][y]) {
                    coords.add(new Coords(x,y));
                }
            }
        }
        collection.add(coords);
        --max;
    }
    return collection;
}

private int getMaxValue(int[][] labels) {
    int max = labels[0][0];
    for (int tabValue[] : labels) {
        for (int value : tabValue) {
            if (max < value) {
                max = value;
            }
        }

    }
    return max;
}

舉個例子 :
我的矩陣包含

[ [ 0, 0, 0 ],  
  [ 1, 1, 1 ],  
  [ 1, 2, 2 ],   
  [ 2, 2, 5 ] ]  

預期結果

ArrayList{ 
  ArrayList{ Coord[0,0], Coord[1,0], Coord[2,0] }, // list of 0 value  
  ArrayList{ Coord[0,1], Coord[1,1], Coord[2,1], Coord[0,3] }, // list of 1 value
  ...
}

您的目標應該是盡可能少地迭代。 如果使用Map構建所需的數據結構,則實際上可以一次(嵌套)迭代來完成。 這里最有用的是TreeMap ,因為它會自動按鍵排序。

邏輯是建立一個new TreeMap<Integer, ArrayList<Coords>>而不是嵌套列表。 Integer鍵是您的值,而arrayList是該值的Coords列表。

您像以前一樣遍歷矩陣,但不計算max 這樣可以節省整個getMaxValue方法和外部while循環。 對於每個值,您首先要檢查TreeMap是否具有帶有該鍵的條目。 如果是,請將新Coord添加到map.get(val)。 如果否,則創建一個new ArrayList<Coord> ,將您的Coord添加到該列表中,然后將其放入地圖中。

如果絕對必須將ArrayList>作為返回類型,則只需在末尾轉換地圖的valueSet,然后return new ArrayList<ArrayList<Coord>>(map.values())

我同意您當前的算法可能效果不佳。 如果您說矩陣的維度為M*N ,則運行時分析可能​​類似於:

max_val = get_max_val(); // O(M*N)
for i from max_val to 0: // O(max_val)
    // O(M*N)
    for x from 0 to M:
        for y from 0 to N:
            do_stuff;

換句話說,這O(M*N*max_val) 如果您的max_val非常大,這很危險; 特別是因為實際的算法不必依賴於價值是什么 (只是哪些是相同的)。

僅取決於MN的替代算法:

HashMap<Integer, ArrayList<Coords>> coordsMap = new HashMap<Integer, ArrayList<Coords>>();
for (int i = 0; i < labels.length; i++) {
    for (int j = 0; j < labels[i].length; j++) {
        if (coordsMap.containsKey(labels[i][j])) {
            ArrayList<Coords> coords = coordsMap.get(labels[i][j]);
            coordsMap.put(labels[i][j], coords.add(new Coords(i, j));
        }
    }
}

// collect results
ArrayList<ArrayList<Coords>> coordsList = new ArrayList<ArrayList<Coords>>();
for (Integer label : coordsMap.keySet()) {
    coordsList.add(coordsMap.get(label));
}
return coordsList;

在此的運行時間為M*N*(HashMap get/put time)

如果要為每個值( from 0 to max_val一個ArrayList,其中用空的ArrayList表示缺少帶有該標簽的坐標,則可以更改// collect results部分,使其類似於:

// collect results
for (int i = 0; i < max_val; i++) {
    if (coordsMap.containsKey(i)) {
        coordsList.add(coordsMap.get(i));
    }
    else {
        coordsList.add(new ArrayList<Coords>());
    }
}

正如Marco13對您的問題的評論所暗示的那樣,實際性能可能在某種程度上取決於您的數據的實際外觀。

當值已經排序后,解決方案就相當簡單:只需遍歷矩陣(按排序順序),並在遇到新值時始終創建一個新列表。

當值排序,那么你就可以創建坐標列表,通過相應的值排序這些,然后采用相同的方法將其像排序情況。

這兩個版本都在這里實現:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortMatrixCoordinates
{
    static class Coords
    {
        int x;
        int y;
        Coords(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
        @Override
        public String toString()
        {
            return "("+x+","+y+")";
        }
    }

    public static void main(String[] args)
    {
        runWithSortedMatrix();
        runWithUnsortedMatrix();
    }

    private static void runWithSortedMatrix()
    {
        int labels[][] = new int[][]{
            { 0, 0, 0 },  
            { 1, 1, 1 },  
            { 1, 2, 2 },   
            { 2, 2, 5 } };

        System.out.println("Result with sorted matrix:");
        List<List<Coords>> result = storeValues(labels);
        for (List<Coords> list : result)
        {
            System.out.println(list);
        }
    }

    private static void runWithUnsortedMatrix()
    {
        int labels[][] = new int[][]{
            { 0, 0, 0 },  
            { 3, 3, 3 },  
            { 3, 2, 2 },   
            { 2, 2, 1 } };

        System.out.println("Result with unsorted matrix:");
        List<List<Coords>> result = storeValuesSorting(labels);
        for (List<Coords> list : result)
        {
            System.out.println(list);
        }
    }

    public static List<List<Coords>> storeValues(final int[][] labels)
    {
        List<List<Coords>> result = new ArrayList<List<Coords>>();
        List<Coords> coords = null;
        int previousValue = 0;
        for (int x = 0; x < labels.length; x++) 
        {
            for (int y = 0; y < labels[0].length; y++) 
            {
                int value = labels[x][y];
                if ((x == 0 && y == 0) || previousValue != value)
                {
                    coords = new ArrayList<Coords>();
                    result.add(coords);
                }
                coords.add(new Coords(x,y));
                previousValue = value;
            }
        }
        return result;
    }


    public static List<List<Coords>> storeValuesSorting(final int[][] labels) 
    {
      List<Coords> sortedCoords = new ArrayList<Coords>();
      for (int x = 0; x < labels.length; x++) 
      {
          for (int y = 0; y < labels[0].length; y++) 
          {
              sortedCoords.add(new Coords(x,y));
          }
      }
      Collections.sort(sortedCoords, new Comparator<Coords>()
      {
          @Override
          public int compare(Coords c0, Coords c1)
          {
              int v0 = labels[c0.x][c0.y];
              int v1 = labels[c1.x][c1.y];
              return Integer.compare(v0, v1);
          }

      });
      List<List<Coords>> result = new ArrayList<List<Coords>>();
      List<Coords> coords = null;
      int previousValue = 0;
      for (int i=0; i<sortedCoords.size(); i++) 
      {
          Coords c = sortedCoords.get(i);          
          int value = labels[c.x][c.y];
          if (i == 0 || previousValue != value)
          {
              coords = new ArrayList<Coords>();
              result.add(coords);
          }
          coords.add(c);
          previousValue = value;
      }
      return result;
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM