这是LeetCode中的一道题目,题目描述如下:
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val
和 next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。
如果是双向链表,则还需要属性 prev
以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList
类:
MyLinkedList()
初始化 MyLinkedList
对象。int get(int index)
获取链表中下标为 index
的节点的值。如果下标无效,则返回 -1
。void addAtHead(int val)
将一个值为 val
的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)
将一个值为 val
的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)
将一个值为 val
的节点插入到链表中下标为 index
的节点之前。如果 index
等于链表的长度,那么该节点会被追加到链表的末尾。如果 index
比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)
如果下标有效,则删除链表中下标为 index
的节点。本次我们选择单链表的实现,所以把题目描述拆分出来:
设计并实现自己的单链表。
单链表中的节点应该具备两个属性:val
和 next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。
假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList
类:
MyLinkedList()
初始化 MyLinkedList
对象。int get(int index)
获取链表中下标为 index
的节点的值。如果下标无效,则返回 -1
。void addAtHead(int val)
将一个值为 val
的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)
将一个值为 val
的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)
将一个值为 val
的节点插入到链表中下标为 index
的节点之前。如果 index
等于链表的长度,那么该节点会被追加到链表的末尾。如果 index
比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)
如果下标有效,则删除链表中下标为 index
的节点。LeetCode提供了函数签名,我们把它写在下面:
class MyLinkedList {
public MyLinkedList() {}
public int get(int index) {}
public void addAtHead(int val) {}
public void addAtTail(int val) {}
public void addAtIndex(int index, int val) {}
public void deleteAtIndex(int index) {}
}
我们的任务:
MyLinkedList()
get()
addAtHead
…到这里准备工作完成了,但是可以想象,这段代码写出来是很难调试的,于是我们自己建立一个java
工程进行调试
大概分为三个class,链表主类、节点类、测试类
节点类是最简单的:
public class ListNode {
int val;
ListNode next;
public ListNode(){
this.val = 0;
}
public ListNode(int val){
this.val = val;
}
public ListNode(int val,ListNode next){
this.val = val;
this.next = next;
}
}
然后是链表主类,先编写基本的初始化函数和一些需要的属性:
public class MySingleLinkedList {
ListNode head;
int length;
public MySingleLinkedList() {
head = new ListNode();
// 笔者编写时犯了一个错误:
// ListNode head = new ListNode();
// 这里的错误!!!
length = 1;
}
}
除了力扣提供的函数,为了方便直观地调试,我们额外编写两个函数:print
函数打印链表、manual
手动建表
public void print(){
ListNode cur = head;
while(cur != null){
if(cur != head){
System.out.print("->");
}
System.out.print("【"+ cur.val +"】");
cur = cur.next;
}
System.out.println();
}
public void manualCreatList(){
// 手动建表
ListNode node1 = new ListNode(2);
ListNode node2 = new ListNode(4);
ListNode node3 = new ListNode(6);
head.val = 0;
head.next = node1;
node1.next = node2;
node2.next = node3;
length = 4;
}
然后我们可以开始写第一个要求的函数:取值函数。但是取值函数测试是否正确?我们还要写个测试函数:
public class TestMain {
public static void main(String[] args) {
MySingleLinkedList list = new MySingleLinkedList();
list.manualCreatList();
list.print();
int num = list.get(2);
System.out.println(num);
}
}
public int get(int index) {
if(index > length-1 || index < 0){
//索引有效性检查
return -1;
}else{
ListNode cur = head;
// ListNode cur = new ListNode();
// 需要对cur节点进行初始化
for(int i=0 ; i<index ; i++){
cur = cur.next;
}
return cur.val;
}
}
public void addAtHead(int val) {
if(length == 0){
head = new ListNode(val);
}else{
int hVal = head.val;
ListNode node = new ListNode(hVal);
head.val = val;
node.next = head.next;
head.next = node;
}
length++;
}
public void addAtTail(int val) {
if(length == 0){
head = new ListNode(val);
}else{
ListNode node = new ListNode(val);
ListNode cur = head;
while(cur.next != null){
cur = cur.next;
}
cur.next = node;
}
length++;
}
public void addAtIndex(int index, int val) {
boolean lenValid = length >= 0;
boolean idxValid = index <= length && index >= 0;
if(lenValid && idxValid){
if(length == 0){
head = new ListNode(val);
}else{
if(index == 0){
addAtHead(val);
return;
}else if(index == length){
addAtTail(val);
return;
}else if(index < length){
ListNode node = new ListNode(val);
ListNode cur = head;
for(int i=0 ; i<index-1 ; i++){
cur = cur.next;
}
node.next = cur.next;
cur.next = node;
}
}
length++;
}
}
public void deleteAtIndex(int index) {
boolean lenValid = length > 0;
boolean idxValid = index < length && index >= 0;
ListNode cur = head;
if(lenValid && idxValid){
if(index == 0 || index == length-1){
// 删除首尾节点
if(index == 0) head = head.next;
if(index == length-1){
for(int i=0 ; i<index-1 ; i++){
cur = cur.next;
}
cur.next = null;
}
}else{
// 删除中间节点
for(int i=0 ; i<index-1 ; i++){
cur = cur.next;
}
cur.next = cur.next.next;
}
length--;
}
}
MySingleLinkedList.java
public class MyLinkedList {
ListNode head;
int length;
public MyLinkedList () {
head = null;
length = 0;
}
public int get(int index) {
boolean lenValid = length > 0;
boolean idxValid = index < length && index >= 0;
int result;
if(head == null) return -1;
if(!lenValid || !idxValid){
result = -1;
}else{
ListNode cur = head;
for(int i=0 ; i<index ; i++){
cur = cur.next;
}
result = cur.val;
}
return result;
}
public void addAtHead(int val) {
if(length == 0){
head = new ListNode(val);
}else{
int hVal = head.val;
ListNode node = new ListNode(hVal);
head.val = val;
node.next = head.next;
head.next = node;
}
length++;
}
public void addAtTail(int val) {
if(length == 0){
head = new ListNode(val);
}else{
ListNode node = new ListNode(val);
ListNode cur = head;
while(cur.next != null){
cur = cur.next;
}
cur.next = node;
}
length++;
}
public void addAtIndex(int index, int val) {
boolean lenValid = length >= 0;
boolean idxValid = index <= length && index >= 0;
if(lenValid && idxValid){
if(length == 0){
head = new ListNode(val);
}else{
if(index == 0){
addAtHead(val);
return;
}else if(index == length){
addAtTail(val);
return;
}else if(index < length){
ListNode node = new ListNode(val);
ListNode cur = head;
for(int i=0 ; i<index-1 ; i++){
cur = cur.next;
}
node.next = cur.next;
cur.next = node;
}
}
length++;
}
}
public void deleteAtIndex(int index) {
boolean lenValid = length > 0;
boolean idxValid = index < length && index >= 0;
ListNode cur = head;
if(lenValid && idxValid){
if(index == 0 || index == length-1){
// 删除首尾节点
if(index == 0) head = head.next;
if(index == length-1){
for(int i=0 ; i<index-1 ; i++){
cur = cur.next;
}
cur.next = null;
}
}else{
// 删除中间节点
for(int i=0 ; i<index-1 ; i++){
cur = cur.next;
}
cur.next = cur.next.next;
}
length--;
}
}
public void print(){
ListNode cur = head;
while(cur != null){
if(cur != head){
System.out.print("->");
}
System.out.print("【"+ cur.val +"】");
cur = cur.next;
}
System.out.println();
}
public void manualCreatList(){
// 手动建表
ListNode node1 = new ListNode(2);
ListNode node2 = new ListNode(4);
ListNode node3 = new ListNode(6);
head.val = 0;
head.next = node1;
node1.next = node2;
node2.next = node3;
length = 4;
}
}