【问题标题】:Advanced array sorting/re-arranging in JavaJava中的高级数组排序/重新排列
【发布时间】:2011-10-20 12:17:01
【问题描述】:

所以我有一个具有以下理论值的数组:

int[] elements = {A1, A2, B1, B2,
                  A3, A4, B3, B4,
                  C1, C2, D1, D2,
                  C3, C4, D3, D4};

图解:

                  + - + - + - + - +
                  | A | A | B | B |
                  + - + - + - + - +
                  | A | A | B | B |
                  + - + - + - + - +
                  | C | C | D | D |
                  + - + - + - + - +
                  | C | C | D | D |
                  + - + - + - + - +

简单地说我想把数组重新排列成下面的形式:

int[] elements = {A1, A2, A3, A4,
                  B1, B2, B3, B4,
                  C1, C2, C3, C4,
                  D1, D2, D3, D4};

图解:

                  + - + - + - + - +
                  | A | A | A | A |
                  + - + - + - + - +
                  | B | B | B | B |
                  + - + - + - + - +
                  | C | C | C | C |
                  + - + - + - + - +
                  | D | D | D | D |
                  + - + - + - + - +

这个特定示例包含四个扇区(A、B、C 和 D),但无论数组包含多少扇区,以及每个扇区包含多少元素,我需要的算法都应该适用。

每个扇区的大小是已知的(扇区宽度和扇区高度)以及扇区的数量(行和列)。 所有扇区的大小(宽度和高度)完全相同。扇区的数量必须描述为两个值(行和列),然后将它们相乘以构成扇区的实际总和。例如。如果需要 5 个扇区,则可以指定 1 行 5 列。

下面是一个执行这种方法的示例:

public int[] sectorSort(int[] elements,
                        int sectorWidth,
                        int sectorHeight,
                        int columns,
                        int rows);

其他扇区设置示例:

                  Columns: 5
                  + - + - + - + - + - + - + - + - + - + - +
                  | A | A | B | B | C | C | D | D | E | E |
     Rows: 1      + - + - + - + - + - + - + - + - + - + - +
                  | A | A | B | B | C | C | D | D | E | E |
                  + - + - + - + - + - + - + - + - + - + - +

                  Columns: 2
                  + - + - + - + - +
                  | A | A | B | B |
                  + - + - + - + - +
                  | A | A | B | B |
                  + - + - + - + - +
                  | C | C | D | D |
     Rows: 3      + - + - + - + - +
                  | C | C | D | D |
                  + - + - + - + - +
                  | E | E | F | F |
                  + - + - + - + - +
                  | E | E | F | F |
                  + - + - + - + - +

我计划使用它为我正在制作的游戏引擎制作一个高效的精灵地图类。数组中的元素是 ARGB 颜色值,扇区是单独的精灵。如果不同的 sprite 按后一种顺序排列,那么搜索单个 sprite 会更快并且内存效率更高。

谢谢!

EDIT1:清晰度。

EDIT2:添加了更多条件和说明。

【问题讨论】:

  • 是否保证所有扇区大小相同?
  • 能否请您添加 5 个扇区的示例,因为我无法想象超过 4 个扇区的情况。
  • @Ralph:我可以看到平方数在我脑海中的样子(4、9、16),但我无法可靠地想象其他任何东西......如果它是 6,它是否设置在3x2 还是 2x3 配置?
  • 好吧,我忘记了一些条件。我现在正在添加它们。谢谢!
  • 您要重新排列现有数组,还是返回一个已排列内容的新数组?

标签: java arrays sorting


【解决方案1】:

你不会得到比这更好的时间复杂度: 它创建一个新数组并将每个扇区复制到其中。

static T[] sectorSort<T>(T[] elements, int sectorWidth, int sectorHeight, int columns, int rows)
        {
            T[] sortedElements = new T[elements.Length];
            int n = 0;
            int arrWidth = sectorWidth * columns;
            for(int secY = 0; secY < rows; secY++)
                for (int secX = 0; secX < columns; secX++)
                {
                    int baseIndex = secY * arrWidth * sectorHeight + secX * sectorWidth;
                    for(int y = 0; y < sectorHeight; y++)
                        for (int x = 0; x < sectorWidth; x++)
                        {
                            int sourceIndex = baseIndex + y * arrWidth + x;
                            sortedElements[n++] = elements[sourceIndex];
                        }
                }
            return sortedElements;
        }

我仍然可以看到很多可以完成的优化,但是阅读你的问题我发现这是在加载时间完成的,所以不要大惊小怪。

编辑:固定代码

EDIT2:测试设置 (C#)

    int[] array = new int[]
    {
        11, 12, 13, 21, 22, 23, 51, 52, 53,
        14, 15, 16, 24, 25, 26, 54, 55, 56,
        17, 18, 19, 27, 28, 29, 57, 58, 59,
        31, 32, 33, 41, 42, 43, 61, 62, 63,
        34, 35, 36, 44, 45, 46, 64, 65, 66,
        37, 38, 39, 47, 48, 49, 67, 68, 69,
        71, 72, 73, 81, 82, 83, 91, 92, 93,
        74, 75, 76, 84, 85, 86, 94, 95, 96,
        77, 78, 79, 87, 88, 89, 97, 98, 99,
    };
    int[] sorted = sectorSort(array, 3, 3, 3, 3);
    for (int y = 0; y < 9; y++)
    {
        for (int x = 0; x < 9; x++)
            Console.Write(sorted[x + y * 9] + " | ");
        Console.WriteLine("\n");
    }

【讨论】:

  • 是的,这就是我所说的直截了当的算法 :) +1 写下来!
  • 你比我走得更远,但算法没有给我正确的结果。给它 [11, 12, 21, 22, 13, 14, 23, 24, 31, 32, 41, 42, 33, 34, 43, 44] 使它返回 [11, 12, 13, 14, 21, 22, 23, 24, 13, 14, 31, 32, 23, 24, 41, 42] 。前两个扇区排序正确,但其他两个扇区排序不正确。
  • 非常感谢!像魅力一样工作!
  • 嗯,它适用于 2x2 扇区。我在 3x3 上尝试过,其中每个扇区由 3x3 值组成。一切都变得不对劲了。我会调查你的代码。 ;)
  • 3x3,3x3 扇区对我来说效果很好。您是否为扇区宽度、扇区高度、列和行设置了正确的值?我将添加我的测试设置。
【解决方案2】:

您可以采用直接的算法迭代所有扇区和其中的所有元素以重新排列它们。这将是 O(n*m),n = 扇区数,m = 每个扇区的元素数。但是您必须重新排列整个数组。作为替代方案(如果内存很关键),您可以创建原始数组的基于扇区的视图,这将花费 O(n) 来创建视图,然后 O(m) 来读取单个扇区的值。

因此,在这两种情况下,读取所有扇区都需要 O(n*m)。您期望有什么改进?

【讨论】:

  • 假设我想要扇区 D 中的所有值,那么我需要使用一种算法来遍历并按顺序找到适当的值并返回它们。这不是一个非常困难的操作,但是如果要非常频繁地执行它,那么它会比如果 D 扇区中的所有值都紧挨着彼此紧挨着要慢得多。您只需要知道第一个在哪里以及有多少个值。我尝试了几次你的方法,但我无法让它发挥作用。我需要更多的例子。
猜你喜欢
  • 2021-01-30
  • 2014-01-04
  • 2011-02-03
  • 2014-08-28
  • 2012-08-11
  • 2015-08-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多