链表的初始化
1.对于链表的初始化,首先你得有一个链表,然后进行初始化链表的数据域和指针域,再一个要有一个构造方法对链表的数据进行赋值。

2.再这里我创建三个Java Class, 第一个就是具体操作的代码类,MySingleLinkedList ,第二个就是这个类的Test类 Test_MySingleLinkedList 用于对各个操作进行执行和检验,第三个就是对其中一个操作的补充 自定义异常类 ListIndexOutOfException。
3.下面是初始化链表的代码实现
public class MySingleLinkedList {
static class ListNode{
public int val; //数据域
public ListNode next; //指针域
public ListNode(int val){ //构造方法(对链表进行初始赋值)
this.val = val;
}
}
public ListNode head; // 头结点
链表的创建
既然链表的东西都有了,那么我们就可以创建一个链表以便于对以后操作的实现。
//创建链表
public void createLink() {
ListNode listNode1 = new ListNode(88); //进行实例化赋值
ListNode listNode2 = new ListNode(7);
ListNode listNode3 = new ListNode(15);
ListNode listNode4 = new ListNode(29);
ListNode listNode5 = new ListNode(16);
head = listNode1; //将链表的头结点地址记录下来
listNode1.next = listNode2; //将每一个结点连接起来成为链表
listNode2.next = listNode3;
listNode3.next = listNode4;
listNode4.next = listNode5;
listNode5.next = null; //最后的地址置空
}

特别注意(对于next的说明):

遍历链表
将链表展示出来,由于单链表是单向移动的,所以要定义一个结点,让它来进行移动,若不进行这样操作链表就会缺失。

如上图,再次执行别的操作就无法知道前面的结点了。
实质
遍历链表其实就是将cur一直向后面走,直到它为空为止。
//遍历链表
public void display(){
ListNode cur;
cur = head;
while (cur != null){ //注意此处cur和cur.next的区别
System.out.print(cur.val+" "); //注意此处cur.val和cur.next.val的区别
cur = cur.next;
}
System.out.println();
}
注意:cur != null 和 cur.next != null 是不一样的,当两者循环执行到末尾时,如下图

public class Test_MySingleLinkedList {
public static void main(String[] args) {
MySingleLinkedList mySingleLinkedList = new MySingleLinkedList();
mySingleLinkedList.createLink(); //创建链表
mySingleLinkedList.display(); //遍历链表

指定位置输出链表
从指定位置输出链表其实就是将遍历这个方法重写,给这个方法设定一个参数newhead,将newhead给cur,让cur遍历即可。
// 从指定位置开始打印链表
public void display(ListNode newHead) { //进行display方法的重写
ListNode cur;
cur = newHead; //将指定位置传给cur
while (cur != null){
System.out.print(cur.val+" ");
cur = cur.next;
}
System.out.println();
}
在此处,newhead在Test这个类中应被赋予新的位置(即指定的位置),例如:newhead = listNode3; newhead = listNode4; 等等。
查找关键字key是否在链表中

//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
ListNode cur = head;
while (cur != null){
if(cur.val == key){
return true;
}else {
cur = cur.next;
}
}
return false;
}
计算链表的长度
链表的长度计算就是将链表进行遍历,在遍历过程中设置一个计算器即可(cunt),若链表不为空,则cunt++; cur向后面移动,直到cur为空为止并返回cunt。注意当cur == null;即链表为空,则return 0;
//计算单链表的长度
public int size(){
ListNode cur = head;
int count = 0;
if(cur == null){
return 0;
}
while (cur != null){
count++;
cur = cur.next;
}
return count;
}
在测试类中进行测试:
//查找是否包含关键字key是否在单链表当中
boolean ret = mySingleLinkedList.contains(15);
System.out.println(ret);
System.out.println("=======================");
//计算单链表的长度
int ret1 = mySingleLinkedList.size();
System.out.println(ret1);
System.out.println("=======================");

头插
对于头插法,首先要创建一个待插入的结点,然后只需调整head和结点的指针域。

//头插法
public void addFirst(int data){
ListNode listNode = new ListNode(data); //新建一个列表,赋值为data
listNode.next = head;
head = listNode;
}
在此不需要判断链表是否为空,当链表为空的时候不影响代码和最后的结果。
尾插
尾插法,首先创建一个待插入结点,那么要进行插入,要找到这个链表的尾巴,然后才能插入。将创建的这个结点的地址给到链表尾巴结点的指针域,这样就连接起来了。注意当链表为空时,只需将创建结点的地址给head即可。

//尾插法
public void addLast(int data){
ListNode listNode = new ListNode(data);
ListNode cur = head;
if (cur == null){ //链表为空
cur = listNode;
return;
}
while (cur.next != null){ //首先要找到尾
cur = cur.next;
}
cur.next = listNode;
listNode.next = null;
}
任意位置插入
1.创建待插入结点,检验插入的位置(index)是否合法。
2.若插入位置为0(链表为空一个道理),则为头插,调用方法
3.若插入位置为链表长度size(),则为尾插,调用尾插
4.当为链表中间位置时,找到插入位置的前一个结点(因为是单链表,无法向前移动)
5.将 ListNode.next == cur.next; 将cur.next == ListNode
6.在此我将判断位置是否合法,寻找index的前一个结点分别写了两个方法,若对于插入位置不合法我使用异常来处理,单独创建了一个异常类


//任意位置插入(第一个结点的下标为0)
public void addIndex(int index,int data){
checkIndex(index); //检验是否合法
ListNode listNode = new ListNode(data);
if(index == 0){ //前插
addFirst(data);
return;
}
if(index == size()){ //尾插
addLast(data);
return;
}
ListNode cur = FindIndex(index); //查找index位置
listNode.next = cur.next;
cur.next = listNode;
}
//检验插入位置是否合法
private void checkIndex(int index){
if(index<0 || index>size()){ //当位置小于0,位置超出链表大写,报异常
throw new ListIndexOutOfException("位置不合法");
}
}
//查找index-1位置
private ListNode FindIndex(int index){
ListNode cur = head;
int count = 0;
while (count != index-1 ){ //此处注意要找到插入位置的前一个结点
cur = cur.next;
count++;
}
return cur;
}
public class ListIndexOutOfException extends RuntimeException { //自定义异常类
public ListIndexOutOfException(String message) {
super(message);
}
}
现在来对头插 尾插 任意位置插入进行测试:
//头插法
mySingleLinkedList.addFirst(31);
mySingleLinkedList.display();
System.out.println("========上面为头插===============");
//尾插法
mySingleLinkedList.addLast(41);
mySingleLinkedList.display();
System.out.println("=========上面为尾插===============");
//任意位置插入
mySingleLinkedList.addIndex(2,51);
mySingleLinkedList.display();
System.out.println("===========上面为任意位置插入=========");

删除第一个为key的结点
1.若链表为空,返回
2.若链表的头结点就是key,只需将head向后移
3. 若key在1,2点以外的位置,首先要找到key的前一个结点(还是由于单链表,无法向前移),然后将cur.next = cur.next.next; 即可。

//删除第一个为key的结点
public void remove(int key){
if (head == null){
return;
}
if(head.val == key){
head = head.next; //注意此处头结点是head,永远以head为链表的开端,若使用cur即链表开端还是head,无法删除链表的头结点
return;
}
ListNode cur1 = FindPrev(key);
if(cur1 == null){
return;
}
cur1.next = cur1.next.next;
}
//寻找key的位置(找到前一个结点)
private ListNode FindPrev(int key){
ListNode cur = head;
while (cur != null){
if(cur.next.val == key){
return cur; //找到了
}
cur = cur.next;
}
return null; //链表中无key值
}
//任意位置插入
mySingleLinkedList.addIndex(2,51);
mySingleLinkedList.display();
System.out.println("===========上面为任意位置插入=========");
////删除第一次出现关键字为key的节点
mySingleLinkedList.remove(88);
mySingleLinkedList.display();
System.out.println("========================");

删除所有为key的结点
1.要删除所有为key的结点显然一个指针是不够的,采用双指针法,prev和cur

2.若链表为空,返回即可
3.若cur.val为key,就删除,将cur.next 赋给 prev.next, cur向后走

4.若不是prev和cur一起往后走 prev = cur; cur = cur.next;

5.若头结点就是key,只需将head后移

//删除链表中所有为key的结点
public void removeAllKey(int key){
if(head == null) {
return;
}
ListNode prev = head;
ListNode cur = head.next;
while (cur != null) {
if(cur.val == key) {
prev.next = cur.next;
cur = cur.next;
}else {
prev = cur;
cur = cur.next;
}
}
if(head.val == key) {
head = head.next;
}
}
//删除链表中所有为key的结点
mySingleLinkedList.removeAllKey(31);
mySingleLinkedList.display();
System.out.println("=========================");
清空链表(回收所有结点)
将头置空
// 回收所有结点
public void clear() {
head = null;
}
整体实现
1.操作类
public class MySingleLinkedList {
static class ListNode{
public int val; //数据域
public ListNode next; //指针域
public ListNode(int val){
this.val = val;
}
}
public ListNode head; // 头结点
//创建链表
public void createLink() {
ListNode listNode1 = new ListNode(88);
ListNode listNode2 = new ListNode(7);
ListNode listNode3 = new ListNode(15);
ListNode listNode4 = new ListNode(29);
ListNode listNode5 = new ListNode(16);
head = listNode1;
listNode1.next = listNode2;
listNode2.next = listNode3;
listNode3.next = listNode4;
listNode4.next = listNode5;
listNode5.next = null;
}
//遍历链表
public void display(){
ListNode cur;
cur = head;
while (cur != null){ //注意此处cur和cur.next的区别
System.out.print(cur.val+" "); //注意此处cur.val和cur.next.val的区别
cur = cur.next;
}
System.out.println();
}
// 指定位置输出链表
public void display(ListNode newHead) {
ListNode cur;
cur = newHead;
while (cur != null){
System.out.print(cur.val+" ");
cur = cur.next;
}
System.out.println();
}
//链表是否存在key
public boolean contains(int key){
ListNode cur = head;
while (cur != null){
if(cur.val == key){
return true;
}else {
cur = cur.next;
}
}
return false;
}
//计算单链表的长度
public int size(){
ListNode cur = head;
int count = 0;
if(cur == null){
return 0;
}
while (cur != null){
count++;
cur = cur.next;
}
return count;
}
//头插法
public void addFirst(int data){
ListNode listNode = new ListNode(data); //新建一个列表,赋值为data
listNode.next = head;
head = listNode;
}
//尾插法
public void addLast(int data){
ListNode listNode = new ListNode(data);
ListNode cur = head;
if (cur == null){
cur = listNode;
return;
}
while (cur.next != null){ //首先要找到尾
cur = cur.next;
}
cur.next = listNode;
listNode.next = null;
}
//任意位置插入,第一个结点下标为0
public void addIndex(int index,int data){
checkIndex(index); //检验是否合法
ListNode listNode = new ListNode(data);
if(index == 0){ //前插
addFirst(data);
return;
}
if(index == size()){ //尾插
addLast(data);
return;
}
ListNode cur = FindIndex(index); //查找index位置
listNode.next = cur.next;
cur.next = listNode;
}
//检验插入位置是否合法
private void checkIndex(int index){
if(index<0 || index>size()){
throw new ListIndexOutOfException("位置不合法");
}
}
//查找index位置 (找到前一个结点)
private ListNode FindIndex(int index){
ListNode cur = head;
int count = 0;
while (count != index-1 ){ //此处注意要找到插入位置的前一个结点
cur = cur.next;
count++;
}
return cur;
}
//删除第一个为key的结点
public void remove(int key){
if (head == null){
return;
}
if(head.val == key){
head = head.next; //注意此处头结点是head,永远以head为链表的开端,若使用cur即链表开端还是head,无法删除链表的头结点
return;
}
ListNode cur1 = FindPrev(key);
if(cur1 == null){
return;
}
cur1.next = cur1.next.next;
}
//寻找key的位置(找到前一个结点)
private ListNode FindPrev(int key){
ListNode cur = head;
while (cur != null){
if(cur.next.val == key){
return cur; //找到了
}
cur = cur.next;
}
return null; //链表中无key值
}
//删除链表中所有为key的结点
public void removeAllKey(int key){
if(head == null) {
return;
}
ListNode prev = head;
ListNode cur = head.next;
while (cur != null) {
if(cur.val == key) {
prev.next = cur.next;
cur = cur.next;
}else {
prev = cur;
cur = cur.next;
}
}
if(head.val == key) {
head = head.next;
}
}
// 回收所有结点
public void clear() {
head = null;
}
}
2.测试类
public class Test_MySingleLinkedList {
public static void main(String[] args) {
MySingleLinkedList mySingleLinkedList = new MySingleLinkedList();
mySingleLinkedList.createLink(); //创建链表
mySingleLinkedList.display(); //遍历链表
//查找是否包含关键字key是否在单链表当中
boolean ret = mySingleLinkedList.contains(15);
System.out.println(ret);
System.out.println("=======================");
//计算单链表的长度
int ret1 = mySingleLinkedList.size();
System.out.println(ret1);
System.out.println("=======================");
//头插法
mySingleLinkedList.addFirst(31);
mySingleLinkedList.display();
System.out.println("========上面为头插===============");
//尾插法
mySingleLinkedList.addLast(41);
mySingleLinkedList.display();
System.out.println("=========上面为尾插===============");
//任意位置插入
mySingleLinkedList.addIndex(2,51);
mySingleLinkedList.display();
System.out.println("===========上面为任意位置插入=========");
////删除第一次出现关键字为key的节点
mySingleLinkedList.remove(88);
mySingleLinkedList.display();
System.out.println("========================");
//删除链表中所有为key的结点
mySingleLinkedList.removeAllKey(31);
mySingleLinkedList.display();
System.out.println("=========================");
//回收全部结点
mySingleLinkedList.clear();
mySingleLinkedList.display();
System.out.println("----------------");
}
}
3.自定义异常类
public class ListIndexOutOfException extends RuntimeException {
public ListIndexOutOfException(String message) {
super(message);
}
}
4.运行结果

1189

被折叠的 条评论
为什么被折叠?



