为什么我们要在声明中的索引 i 处初始化列表 List<List<Integer>> 图形



考虑一个情况,我们可以在List<List<Integer>>的帮助下定义一个图,其中索引 0 处的列表将是顶点 0 的邻接列表,依此类推 1,2,3 及更远。

现在,如果我声明这样的邻接列表如下,

// initialize adjacency list
List<List<Integer>> adjList = new ArrayList<List<Integer>>(n);

在这种情况下,为什么我需要初始化每个列表,如下所示,

// initialize vertices
for (int i = 0; i < n; i++)
adjList.add(i, new ArrayList<Integer>());

此循环仅在每个索引 i 处添加一个新列表,其中 n = 图中的顶点数。

初始声明是否意味着主列表将在索引 0 处有一个列表,然后在索引 1 处再次具有另一个列表,依此类推?

我的意思是,如果我在列表数组的帮助下声明一个图形,我可以理解这个循环的使用,如下所示,

ArrayList[] graph = new ArrayList[n];

那么在这种情况下,是的,我肯定需要一个循环来初始化每个顶点的邻接列表,但为什么我们也需要在这种初始情况下初始化呢?

如果我按如下方式声明数组怎么办?这会对循环产生任何影响吗?

1. List<List<Integer>> adjList = new ArrayList<>(n);
2. List<List<Integer>> adjList = new ArrayList<List<List<Integer>>(n);

请帮助我,我为了理解这一点而犯的概念错误是什么?

当你有:

List<List<Integer>> adjList = new ArrayList<List<Integer>>(n);

您只实例化了初始容量nArrayList,但列表为空(即adjList.size() == 0(。ArrayList的容量是其内部阵列的大小。当你向ArrayList添加元素时,如果数组不够大,无法容纳另一个元素,则必须创建一个新的、更大的数组,并且必须复制旧数组的内容。这可能很昂贵;如果您知道所需的容量,则可以指定初始容量,以避免"调整"内部阵列的大小。

如果List必须有一定数量的元素开始,你必须首先添加它们,这就是循环的作用:

for (int i = 0; i < n; i++)
adjList.add(i, new ArrayList<Integer>());

以下是List#add(int,E)的文档:

在此列表中的指定位置插入指定的元素(可选操作(。将当前位于该位置的元素(如果有(和任何后续元素向右移动(将一个元素添加到其索引中(。

由于您从一个空List开始,然后从0迭代到n因此您只需在每次迭代List末尾添加一个元素。这相当于每次迭代都调用List#add(E)。循环完成后,您将拥有一个大小等于n的非空List


如果我按如下方式声明数组怎么办?这会对循环产生任何影响吗?

1. List<List<Integer>> adjList = new ArrayList<>(n);
2. List<List<Integer>> adjList = new ArrayList<List<List<Integer>>(n);
  1. 这只是使用钻石运算符。菱形运算符在使用泛型类型时删除样板。
  2. 这不会编译;左侧是列表列表,但右侧是列表列表。

相关内容

最新更新