目录
任务内容
1、Java是如何构造链表
2、链表如何进行增删改查
一、Java如何构造链表
构建出节点对象
public class ListNode{
public int var;//节点值
public ListNode next;//节点的后继节点
public ListNode(int var){//节点带参构造方法
this.var = var;
}
}
根据已有数组,遍历数组,构建链表
public static void main(String[] args) {
int[] a = {1,3,5,7,9,11};
ListNode head = initListNode(a);
System.out.println(outputList(head));
}
private static ListNode initListNode(int[] array){
ListNode head = null,cur = null;//初始化头节点,当前节点
for (int i = 0; i < array.length; i++) {
//为数组中每个值创造一个节点
ListNode node = new ListNode(array[i]);
if (i == 0){//从第一个节点开始,头节点head不变,变动cur节点
head = node;
cur = node;
}else{
cur.next = node;
cur = node;
}
}
return head;
}
二、链表的增删改查
1.遍历链表
就单链表来说,不论什么操作,都是要从链表的头节点开始向后一个个节点访问,再进行操作,故,链表的头节点非常重要,一定要记牢。
1.1获取链表长度
/**
* 获取链表长度
* @param head 头节点
* @return 链表长度
*/
public static int getListLength(ListNode head){
int length = 0;//用于计数
ListNode cur = head;//一般创造一个临时指针来代替头节点向后遍历(牢记:头节点需谨慎改变)
while (cur != null){
length ++;
cur = cur.next;
}
return length;
}
1.2遍历链表节点值
借用stringbuilder类来输出链表
/**
* 遍历输出链表
* @param head 头节点
* @return 链表输出形式
*/
public static String outputList(ListNode head){
StringBuilder sb = new StringBuilder();
ListNode cur = head;
while (cur != null){
if (cur.next == null)
sb.append(cur.var);
else
sb.append(cur.var).append("->");
cur = cur.next;
}
return sb.toString();
}
2.链表插入
链表插入有三种方法
2.1 头插法
头节点很重要,在头部插入新节点后,需要改变head指向新链表表头。
2.2 中间插入
中间插入节点,必须从头节点开始遍历找到要插入的位置,记住确认插入位置的前驱节点(这非常重要)。保持先来先主动原则:首先新节点的后继先接入,然后再使新节点的前驱节点接入新节点,例如下图:记住cur = node(15),首先new.next = node(7),然后cur.next = new
2.3 尾部插入
只需将遍历链表,将尾节点指向新节点就行。
实现代码
/**
* 插入节点
* @param head 头节点
* @param newNode 待插入节点
* @param position 待插入位置,从1开始
* @return 插入后得到的链表头节点
*/
public static ListNode insertNewNode(ListNode head,ListNode newNode,int position){
if (head == null){//如果链表为空,则插入节点就是链表的头节点
head = newNode;
return newNode;
}
int size = getListLength(head);//得到已经存放的节点个数
if (position > size+1 || position < 1){ //判断插入位置是否合法
System.out.println("位置参数越界");
return head;
}
//表头插入
if (position == 1){
newNode.next = head;
head = newNode; //更新表节点
return head;
}
// 表中和表尾插入
int count = 1; //设一个计数,便于寻找所插入位置的前一个节点
ListNode cur = head; //从头节点开始寻找
while (count < position - 1){ //例如,position == 3 ,找到第二个节点即可,count == 2结束循环,故count < 2(position -1)作为条件
count ++;
cur = cur.next;
}
//插入节点具体操作
newNode.next = cur.next;
cur.next = newNode;
System.out.println("在链表第" +position+"个位置,插入节点"+newNode.var+"成功");
return head;
}
3.链表删除
3.1 删除表头节点
只需将头节点head更新为head.next就行。jvm有gc回收机制,没用地址引用会直接清楚堆中对象。
3.2 删除中间节点
找到删除节点位置的前驱节点,用于cur引用标记,将cur.next = cur.next.next。
3.3 删除尾节点
同删除中间节点也可实现,或者cur.next = null
实现代码
/**
* 删除节点
* @param head 头节点
* @param position 删除节点位置,取值从1开始
* @return 删除后的链表头节点
*/
public static ListNode deleteListNode(ListNode head,int position){
if (head == null){
System.out.println("该链表为空,没有可删除的节点");
return null;
}
int size = getListLength(head);
if (position > size || position <1){
//思考一下,这里为什么是size,而不是size+1
//因为插入节点时,可插入第size+1位置,而删除节点不能删除size+1位置。
System.out.println("输入位置参数有误");
return head;
}
//删除表头节点
if (position == 1){
head = head.next;
return head;
}else {
//删除表中和表尾节点
ListNode cur = head;
int count = 1;
while (count < position -1){//找到删除节点的前趋节点
count++;
cur = cur.next;
}
//删除节点具体操作
cur.next = cur.next.next;
}
return head;
}
三、扩展题
如果链表是单调递增的,将元素插入到合适的位置,序列仍然保持单调,该如何实现?
思路:同为插入新节点,只需遍历整个链表的节点,每个节点与插入节点值进行大小比较,找到合适的插入位置,再进行链表插入。
例:将数组array{1,3,5,7,9,11}用链表实现。并①插入新节点4,②插入新节点12。
public static void main(String[] args) {
int[] array = {1,3,5,7,9,11};
//初始化链表
Node head = initListNode(array);
//插入新节点4
head = insertNewNode(head,new Node(4));
//插入新节点12
head = insertNewNode(head,new Node(12));
System.out.println(toString(head));
}
/**
* 插入新节点,并保持链表单调
* @param head 头节点
* @param newNode 待插入节点
* @return 插入后的链表头节点
*/
public static Node insertNewNode(Node head,Node newNode){
if (head == null)
return newNode;
Node cur0 = head;//遍历,依次与插入节点比较
Node cur1 = head;//记录插入位置的前一个节点
int count = 0;//记录比较次数,当比较次数达到链表最大长度时,将新节点插入表尾
while (cur0.var <= newNode.var){//遍历链表,节点一一比较,找到待插入位置。
count ++;
if (count >= getListLength(head)){//比较次数达到链表最大长度,说明已经达到链表表尾,将cur1指向表尾即可退出循环。
cur1 = cur0;
break;
}
cur1 = cur0;
cur0 = cur0.next;
}
newNode.next = cur1.next;
cur1.next = newNode;
return head;
}