本篇博客只是简单实现单链表(不带头节点),此类链表头节点会改变,面试遇到的会比较多。此外,只是简单的实现单链表,和原码有很大差距,目的是为了通过简单的实现单链表,对链表的各种操作更加熟悉。以便以后刷链表的题更加的得心应手。
目录
全部代码
MySIngleList
增删查改详解
遍历打印单链表
链表节点个数
头插法:
尾插法:
在指定位置插入节点
查看链表是否包含某个元素
删除第一次出现关键字为key的节点
删除所有值为key的节点
清空链表
public class MySingleList {
//写一个内部类ListNode,表示单链表的节点
static class ListNode{
public int vale;//节点里面的值域
public ListNode next;//节点里面放下一个节点的地址域
//写一个构造方法
public ListNode(int vale) {
this.vale = vale;
}
}
public ListNode head;//头节点
//这里用比较low的方法先创建一个链表,以便学习。
// 下面会写add方法,到时候可以拿add方法创建一个链表
public void creatList(){
ListNode list1 = new ListNode(20);
ListNode list2 = new ListNode(22);
ListNode list3 = new ListNode(10);
ListNode list4 = new ListNode(01);
list1.next = list2;
list2.next = list3;
list3.next = list4;
this.head = list1;
}
//遍历打印单链表
public void display(){
ListNode cur = this.head;
while(cur != null){
System.out.print(cur.vale+" ");
cur = cur.next;
}
System.out.println();
}
//链表节点个数
public int size(){
int count = 0;
ListNode cur = this.head;
while(cur != null){
count++;
cur = cur.next;
}
return count;
}
//头插法
public void addFirst(int data){
ListNode node = new ListNode(data);
node.next = this.head;
head = node;
}
// 尾插法
public void addLast(int data){
ListNode node = new ListNode(data);
if(head == null){
head = node;
}else{
ListNode cur = this.head;
while (cur.next != null){
cur = cur.next;
}
cur.next = node;
}
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
if(index<0 || index > this.size()){
throw new PosWrongFulException("index位置不合法");
}
if(index == 0){
addFirst(data);
return;
}
if(index == this.size()){
addLast(data);
return;
}
ListNode cur = findIndexSubOne(index);
ListNode node = new ListNode(data);
node.next = cur.next;
cur.next = node;
}
private ListNode findIndexSubOne(int index){
ListNode cur = this.head;
while (index-1 != 0){
cur = cur.next;
index--;
}
return cur;
}
//查找是否包含关键字key是否在单链表当中
public boolean conains(int key){
ListNode cur = head;
while(cur != null){
if(cur.vale == key){
return true;
}
cur = cur.next;
}
return false;
}
// 删除第一次出现关键字为key的节点
public void remove(int key){
if(head.vale == key){
head = head.next;
return;
}
ListNode cur = findPrevOfKey(key);
if(cur == null){
System.out.println("没有你要删除的值");
return;
}
cur.next = cur.next.next;
}
private ListNode findPrevOfKey(int key){
ListNode cur = head;
while(cur.next != null){
if(cur.next.vale == key){
return cur;
}
cur = cur.next;
}
return null;
}
// 删除所有值为key的节点
public void removeAllKey(int key){
ListNode pre = head;
ListNode cur = head.next;
while (cur != null){
if(cur.vale == key){
pre.next = cur.next;
cur = cur.next;
}else {
pre = cur;
cur = cur.next;
}
}
if(head.vale == key){
head = head.next;
}
}
public void clear(){
head = null;
}
}
思路:创建一个cur代替head遍历这个链表,把里面的每个元素打印出来
代码
public void display(){
ListNode cur = this.head;
while(cur != null){
System.out.print(cur.vale+" ");
cur = cur.next;
}
}
这里while的终止条件是cur != null,而不是cur.next != null,是因为我们要打印每个节点里面的值。如果是cur.next!=null,最后一个节点不会被打印,且如果是空链表会空指针异常。
(这里的creatList可以看上面写在一起的代码,就是用穷举的方法简单创建了一个单链表,很low,放下面辣)
public void creatList(){
ListNode list1 = new ListNode(20);
ListNode list2 = new ListNode(22);
ListNode list3 = new ListNode(10);
ListNode list4 = new ListNode(01);
list1.next = list2;
list2.next = list3;
list3.next = list4;
this.head = list1;
}
思路:和上面一样,创建一个count用来计数,遍历一下这个链表。
代码:
//链表节点个数
public int size(){
int count = 0;
ListNode cur = this.head;
while(cur != null){
count++;
cur = cur.next;
}
return count;
}
运行结果:
思路
代码:
//头插法
public void addFirst(int data){
ListNode node = new ListNode(data);
node.next = this.head;
head = node;
}
运行结果:
思路:
代码:
public void addLast(int data){
ListNode node = new ListNode(data);
if(head == null){
head = node;
}else{
ListNode cur = this.head;
while (cur.next != null){
cur = cur.next;
}
cur.next = node;
}
}
运行结果:
思路:
代码
public void addIndex(int index,int data){
if(index<0 || index > this.size()){
throw new PosWrongFulException("index位置不合法");
}
if(index == 0){
addFirst(data);
return;
}
if(index == this.size()){
addLast(data);
return;
}
ListNode cur = findIndexSubOne(index);
ListNode node = new ListNode(data);
node.next = cur.next;
cur.next = node;
}
private ListNode findIndexSubOne(int index){
ListNode cur = this.head;
while (index-1 != 0){
cur = cur.next;
index--;
}
return cur;
}
PosWrongFulException
public class PosWrongFulException extends RuntimeException{
public PosWrongFulException() {
}
public PosWrongFulException(String message) {
super(message);
}
}
运行结果:
思路:遍历链表
代码:
public boolean conains(int key){
ListNode cur = head;
while(cur != null){
if(cur.vale == key){
return true;
}
cur = cur.next;
}
return false;
}
运行结果:
思路:
假设我们现在要删除值为22这个节点,那么需要找到值为22的前一个节点,把它的next的域改为22这个节点next域指向的节点。我们可以写一个函数来找到前一个节点pre
pre.next = pre.next.next。还要考虑如果删除的是头节点,则只需要把头节点指向头节点next域指向的节点:head = head.next;
代码
// 删除第一次出现关键字为key的节点
public void remove(int key){
if(head.vale == key){
head = head.next;
return;
}
ListNode cur = findPrevOfKey(key);
if(cur == null){
System.out.println("没有你要删除的值");
return;
}
cur.next = cur.next.next;
}
private ListNode findPrevOfKey(int key){
ListNode cur = head;
while(cur.next != null){
if(cur.next.vale == key){
return cur;
}
cur = cur.next;
}
return null;
}
运行结果:
思路:
假设我现在要删除所有值为20的节点,我们需要2个ListNode变量,因为如果只定义一个 cur,那么如果是连续俩个都是20的节点在一起,就会漏删。原因是当我们把第一个20节点删掉后,cur必须向后走一步,如果此时cur指向的节点的值刚好还是20就删除不了了。
我们可以先判断cur的值是否等于20,如果等于:pre的next域指向cur的next域。cur继续往后走,如果不等于,pre指向cur,cur往后走。
为什么要等cur的值不等于20时再让pre指向cur,cur再往后走。是因为如果cur的值是20,cur需要删除。如果此时另pre = cur,那么pre就不是cur的前驱了。
最后我还需要判断头节点是否等于20,如果需要删除再把头节点删除。head = head.next
代码:
// 删除所有值为key的节点
public void removeAllKey(int key){
ListNode pre = head;
ListNode cur = head.next;
while (cur != null){
if(cur.vale == key){
pre.next = cur.next;
cur = cur.next;
}else {
pre = cur;
cur = cur.next;
}
}
if(head.vale == key){
head = head.next;
}
}
运行结果:
思路:当节点没有对象引用时就会被回收。此时只需要另头结点为空就好。
代码:
public void clear(){
head = null;
}
运行结果