1.理解Java是如何构造出链表的
单链表:每个节点通过 一个next指针指向下一个节点形成的链
/**
简易版本的链表
*/
public class Course{
int val;
// 即指向下一个course的地址
Course next;
}
/**
自定义链表的实现
*/
public class ListNode{
private int data;
private ListNode next;
public ListNode(int data) {
this.data = data;
}
public int getData(){
return data;
}
public void setData(int data){
this.data = data;
}
public ListNodegetNext() {
return next;
}
public void setNext(ListNode next) {
this .next = next;
}
}
/**
leetcode版本
*/
public class ListNode{
public int val;
public ListNode next;
public ListNode(int val){
this.val = val;
//这个作用不大 写了会更规范
next = null;
}
}
2.链表增加元素,首部、中间和尾部分别会有什么问题,该如何处理?
头部添加:新增节点的next指向head节点,把head改为新增节点
尾部添加:尾部元素的next指向新增节点即可
中间添加:需要注意的是我们遍历到要插入位置的时候,需要获取前一个指针,但是单链表没有pre指针,所以通常都需要遍历到添加位置的前一个位置,也就是用cur.next来判断
public Node insert(Node head,Node insertNode,int position){
if(head == null) return null;
//节点个数 伪代码、未实现
int count = getLength(head);
if(position > count + 1 || position < 1){
System.out.println("越界");
return head;
}
// 头部添加
if(position == 1){
insertNode.next = head;
head = insertNode;
return head;
}
Node cur = head;
int curInt = 1;
// count - 1的目的是为了获取插入位置的前一个位置
while(curInt < count - 1){
cur = cur.next;
curInt++;
}
insertNode.next = cur.next;
cur.next = insertNode;
return head;
}
3.链表删除元素,首部、中间和尾部分别会有什么问题,该如何处理?
头部删除:直接把head改为head.next即可
尾部删除:跟中间插入一样 要在删除位置的前一位停下,将next指向null,删除位置的元素没有地方引用 会被JVM回收
中间删除:跟中间插入一样 要在删除位置的前一位停下,将next指向删除位置元素的next,删除元素没有引用 会被JVM回收
public Node delete(Node head,int position){
if(head == null) return null;
//节点个数 伪代码、未实现
int count = getLength(head);
// 这里与插入不一样 大于count就不行 因为插入可以在count + 1那个位置插入元素,
// 但是删除 不能删除 count+1位置的元素 因为count+1位置是null
if(position > count || position < 1){
System.out.println("越界");
return head;
}
// 头部删除
if(position == 1){
head = head.next;
return head;
}
Node cur = head;
int curInt = 1;
// count - 1的目的是为了获取插入位置的前一个位置
while(curInt < count - 1){
cur = cur.next;
curInt++;
}
Node next = cur.next;
cur.next = next.next;
return head;
}
4.双向链表是如何构造的,如何实现元素的插入和删除
双链表:每个节点都有pre、next两个指针分别指向前一个和下一个节点
增删 都要考虑三种情况:头、尾、中
public class DoubleListNode{
public int data;
public DoubleListNode pre;
public DoubleListNode next;
public DoubleListNode(int val){
data = val;
}
// 与单链表不同的是,双链表有pre和next双指针
public void insertFirst(int data){
DoubleListNode node = new DoubleListNode(data);
if(head == null){
// head和last分别是头尾指针 此处未定义
last = node;
}else{
head.pre = node;
node.next = head;
}
head = node;
}
public void insertLast(int data){
DoubleListNode node = new DoubleListNode(data);
if(head == null){
// head和last分别是头尾指针 此处未定义
head = node;
last = node;
}else{
last.next = node;
node.pre = last;
last = node;
}
}
// key表示的是要插入在哪个元素后面的 那个元素的值
public void insertAfter(int key,int data){
DoubleListNode node = new DoubleListNode(data);
DoubleListNode cur = head;
while(cur != null && cur.data != key){
cur = cur.next;
}
if(cur == null){
// 链表为空
if(head == null){
head = node;
last = node;
}else{
// 链表不为空 但是链表没有key这个节点 所以添加在链表最后
last.next = node;
node.pre = last;
last = node;
}
}else{
// 在链表中找到了key这个节点
// 这个节点是最后一个节点
if(cur == last){
node.pre = last;
node.next = null;
last.next = node;
last = node;
}else{
// 此处要注意顺序
node.next = cur.next;
node.pre = cur;
cur.next.pre = node;
cur.next = node;
}
}
}
// 头部删除
public DoubleListNode deleteFirst(){
DoubleListNode cur = head;
if(head == null) return null;
if(head.next == null){
last = null;
}else{
cur.next.pre = null;
cur = cur.next;
}
return cur;
}
// 尾部删除
public DoubleListNode deleteFirst(){
// 获取尾元素
DoubleListNode cur = last;
if(head == null) return null;
if(head.next == null){
head = null;
last = last.pre;
}else{
last.pre.next = null;
last = last.pre;
}
return cur;
}
// 删除中间节点
public DoubleListNode deleteKey(int key){
DoubleListNode cur = head;
while((cur.next != null) && (cur.data != key)){
cur = cur.next;
}
if(head == null){
return null;
}
// 三种情况
if(cur == head){
head = cur.next;
cur.next.pre = null;
}else if(cur == last){
last.pre.next = null;
last = cur.pre;
}else{
cur.pre.next = cur.next;
cur.next.pre = cur.pre;
cur.next = null;
cur.pre = null;
}
return head;
}
}