如何通过数组或字符串直观地创建链表
在前段时间集中做了leetcode上树的相关的题目之后,最近准备做链表相关的题目了。与之前的问题相同,如果每次测试代码的时候,自己创建测试用例,或者调用leetcode给的例子,都要手动去创建一个链表的话,效率未免太低,也会打断做题时候的思路,因此,也整理出了一个用来创建链表的代码,贴出来以供参考。
相关文章
这里有可以参考的创建和直观展示一棵树的方法:
如何直观地打印一棵树
如何直观地创建一棵树
然后是可以直观地打印出一棵树的代码,在本文中也会用到(为方便读者使用,已经将这些代码集成在本文的代码中了,共同作为工具类的方法):
如何直观地打印一个链表
如何创建一个链表
由int数组创建链表
首先,我们先写一个方法,来实现最简单的,由一个给定的数组来创建一个链表:
// 通过数组来构建链表
public static ListNode constructList(int[] nums) {
ListNode dummy = new ListNode(-1);
ListNode preNode = dummy;
for (int i = 0; i < nums.length; i ++) {
ListNode currNode = new ListNode(nums[i]);
preNode.next = currNode;
preNode = preNode.next;
}
return dummy.next;
}
在这个方法中,我们只需要遍历输入的数组,然后根据各个元素创建链表的节点的对象,然后把各个对象链接起来即可。这里用了一个小技巧,就是使用了一个dummy作为链表的起始节点,这样的目的是,使后面所有节点的操作完全相同,否则链表中的第一个节点的操作肯定是与其它节点不同的,这样可以减少冗余代码,提高效率(不同多次判断是否为头节点),并且即使为空,输出的方法也不会改变。
由字符串创建链表
在上面一节,我们有了通过int数组得到了链表的方法,但是实际中更常见的情况是,要通过从网页上复制下来的字符串来构建链表,而字符串又有多种形式,如:
"1->2->3->4->5->NULL"
"[1, 2, 3, 4 ,5]"
有的是用箭头来表示,有的是用一个数组的形式(的字符串)来表示,有的带NULL,有的不带,有的用空格隔开,有的没有,因此,仅仅有上面的由整型数组构建链表的方法远远不够,我们需要一个能够适配更多种形式的字符串的方法才能应对这些情况。
但是,因为我们有了上面的这个方法,因此,可以用统一的思路,即先将字符串处理成整型数组,再调用上面的constructList(int[] nums)
来得到链表。
在这里,对于多种字符串的形式做了适配,具体如下:
- 允许的字符串形式:
"1->2->3->4->5->NULL"
"1->2->3->4->5"
"[1, 2, 3, 4 ,5]"
"[1, 2, 3, 4 ,5, NULL]"
- 注意:
1)字符串前后可以有空格
2)NULL为大写或小写均可
在下面,将最后的代码贴了出来:
// ListOperation.java
public class ListOperation {
// 直观地打印出链表
public static void show(ListNode head) {
if (head == null) {
System.out.println("EMPTY LIST!");
return;
}
ListNode currNode = head;
while (currNode.next != null) {
System.out.print(currNode.val);
System.out.print("->");
currNode = currNode.next;
}
System.out.print(currNode.val);
System.out.println();
}
// 通过数组来构建链表
public static ListNode constructList(int[] nums) {
ListNode dummy = new ListNode(-1);
ListNode preNode = dummy;
for (int i = 0; i < nums.length; i ++) {
ListNode currNode = new ListNode(nums[i]);
preNode.next = currNode;
preNode = preNode.next;
}
return dummy.next;
}
// 根据各种字符串输入,构建链表
/*
允许的字符串形式:
"1->2->3->4->5->NULL"
"1->2->3->4->5"
"[1, 2, 3, 4 ,5]"
"[1, 2, 3, 4 ,5, NULL]"
注意:
1)字符串前后可以有空格
2)NULL为大写或小写均可
*/
public static ListNode constructList(String listStr) {
int[] nums;
String[] numsStrArray;
// 适配形如[1,2,3]的输入
if (listStr.charAt(0) == '[' && listStr.charAt(listStr.length() - 1) == ']') {
listStr = listStr.substring(1, listStr.length() - 1);
numsStrArray = listStr.split(",");
}
// 适配形如1->2->3的输入
else if (listStr.contains("->")) {
numsStrArray = listStr.split("->");
}
// 如果有其他形式的输入,可以在这里进行扩展
else {
numsStrArray = new String[1];
numsStrArray[0] = listStr;
}
// 获取数组nums的长度
int numsLength;
if (numsStrArray.length > 1) {
// 判断最后一位是否为NULL,若是的话,则空过
numsLength = numsStrArray[numsStrArray.length - 1].toLowerCase().contains("null") ? numsStrArray.length - 1 : numsStrArray.length;
}
else
numsLength = 1;
// 构建一个包含所有数字的数组,然后调用被重载的(输入为一个int[]的)构建链表的函数。
nums = new int[numsLength];
for (int i = 0; i < numsLength; i++) {
// 处理输入的字符串中每个数字前后的空格
numsStrArray[i] = numsStrArray[i].replace(" ", "");
nums[i] = Integer.valueOf(numsStrArray[i]);
}
return constructList(nums);
}
}
在上面的代码中,有几点需要注意:
- 这里将几种方法都集成在了一个统一的ListOperation类中,方便调用。
- 第一个
show(ListNode head)
方法,为打印一个链表的方法,来自于:如何直观地打印一个链表,这里也集成了进来,一是方便使用,二是方便对我们创建的链表进行测试。 - 实际上有两个创建链表的方法,一个是’constructList(int[] nums)’,由整型数组创建,一个是
constructList(String listStr)
,由字符串创建,这里用了重载进行处理,对外暴露为同一个方法,方便使用,其具体的使用方法可以看下面的demo。
测试代码:
// ListOperationTest.java
public class ListOperationTest {
public static void main(String[] args) {
ListNode head = ListOperation.constructList(new int[] {1, 2, 3, 4, 5});
System.out.print("head1:\t\t");
ListOperation.show(head);
ListNode head2 = ListOperation.constructList("1->2->3->4->5->NULL");
System.out.print("head2:\t\t");
ListOperation.show(head2);
ListNode head3 = ListOperation.constructList("1->2->3->4->5");
System.out.print("head3:\t\t");
ListOperation.show(head3);
ListNode head4 = ListOperation.constructList("[1, 2, 3, 4 ,5, NULL]");
System.out.print("head4:\t\t");
ListOperation.show(head4);
ListNode head5 = ListOperation.constructList("[1, 2, 3, 4 ,5]");
System.out.print("head5:\t\t");
ListOperation.show(head5);
}
}
程序输出:
head1: 1->2->3->4->5
head2: 1->2->3->4->5
head3: 1->2->3->4->5
head4: 1->2->3->4->5
head5: 1->2->3->4->5
可以看到,这里用了多种常见的链表的形式,都可以正确的创建出对应的链表。