基于Java的链表 常见使用方法

一、链表
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。

1.单向链表
单向链表,它包含两个域,一个信息域和一个指针域。信息域用来存储链表中要存放的值,指针域则指向下一个节点。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。其结构图如下:


2、双向链表
双向链表在单链表的基础上,每个节点新增了一个指针域,用来指向前一个节点。其结构图如下:


二、链表的基本操作
首先创建一个LinkedList类。

0.链表节点的对象
创建一个ListNode类,包含两个属性,一个为链表节点的值,另一个为下一个节点的地址。
创建size属性记录链表长度

public class LinkedList {

	//定义节点
	static class ListNode {
		int val; // 链表存储的值
		ListNode next; // 指针,指向下一个节点
		ListNode() {
			
		}
		ListNode(int val) { 
			this.val = val; 
		}
		ListNode(int val, ListNode next) { 
			this.val = val;
			this.next = next; 
		}
	}
	
	int size; // 链表长度
	ListNode headNode; //链表头结点
	ListNode dummyHead = new ListNode(0);
}

1.头插法
头插法,即在链表首部添加一个节点作为新的头结点。
首先要新建一个ListNode 对象作为要插入的节点,然后根据情况进行操作。如果当前链表为空链表,则将该节点直接作为头结点即可创建一个链表;如果当前链表不是空链表,则将要插入的节点的next指针指向原本的头节点。

	public void headInsertion(int val) {
		ListNode newListNode = new ListNode(); // 新建一个对象,即为要插入的节点
		newListNode.val = val; // 对节点存入要插入的值
		if (headNode == null) { //头结点为空即是个空链表,头结点直接指向要插入的节点即可
			headNode = newListNode;
		} else {
			newListNode.next = headNode; // 要插入的节点应放在第一个,所以它的下一个节点指向head
			headNode = newListNode; // 插入后新插入的节点是新的头结点
		}
		size ++;
	}

2.任意位置插入节点
insert方法为在任意位置插入节点,参数中的index为插入节点的位置,val为插入节点的值,如果index等于0,则和头插法过程相同。否则,需要先找到前一个节点, 将该节点的next指针指向前一个节点next指向的节点,然后再将前一个节点指向该节点。
插入过程图解如下:
(1)创建要插入的节点对象

(2)current节点指向next节点

(3)previous节点指向current节点,完成插入


   

	public void insert(int index, int val) {
		if (index > size) {
			System.out.println("越界");
			return;
		}
		ListNode newListNode = new ListNode(); // 存放添加元素的链表节点
		newListNode.val = val;
		if (index == 0) { // 插入到第0位,和头插法相同
			if (headNode == null) {
				headNode = newListNode;
			} else {
				newListNode.next = headNode;
				headNode = newListNode;
			}
			size ++;		
		} else {
			ListNode prevNode = headNode; // 创建一个指向头结点的指针
			for (int i = 0; i < index-1; i++) {
				prevNode = prevNode.next; // 用该指针找到要添加元素位置的前一个
			}
			newListNode.next = prevNode.next; // 添加的节点的next指针指向要添加位置的下一个
			prevNode.next = newListNode; //前一个节点的next指针指向添加的节点
			size ++;
		}
	}

3.尾插法
先找到原先最后一个节点,然后将其next指向要插入的节点即可。

	public void tailInsertion(int val) {
		ListNode newListNode = new ListNode();
		newListNode.val = val; 
		ListNode prevNode = headNode; // 创建一个指向头结点的指针
		for (int i = 0; i < size-1; i++) {
			prevNode = prevNode.next;// 用该指针找到要最后一个节点的前一个节点
		}
		newListNode.next = prevNode.next;
		prevNode.next = newListNode;
		size ++;
	}

4.删除第index个元素
找到第index-1个节点,将其直接指向第index+1个节点即可。需要注意空链表或者越界情况。
删除过程图解如下:
(1)找到要删除的节点对象current

(2)previous指针指向next节点即可删除。

	public void deleteByIndex(int index) {
		if (index > size) {
			System.out.println("越界");
			return;
		}
		if (headNode == null) {
			System.out.println("空链表");
		} else {
			if (index == 0) { // 删除第一个元素,直接把头结点指向第二个元素即可
				headNode = headNode.next;
				size --;
			} else {
				ListNode prevNode = headNode; // 创建一个指向头结点的指针
				for (int i = 0; i < index-1; i++) {
					prevNode = prevNode.next; // 用该指针找到要删除元素位置的前一个
				}
				System.out.println("delete:"+prevNode.next.val);
				// 要删除的元素的前一个节点的next指针指向下一个节点,完成删除
				prevNode.next = prevNode.next.next; 
				size --;
			}
		}
	}

5.删除val元素
删除值为val的节点,以此遍历找到值为val的节点,并对其删除即可。

	public void deleteByValue(int val) {
		if (headNode == null) {
			System.out.println("空链表");
		} else {
			while(val == headNode.val){// 如果头结点是要删除的元素
				headNode = headNode.next;
				size --;
			}
			ListNode prevNode = headNode; // 创建指针,指向被操作的节点的前一位
			ListNode currentNode = headNode; // 创建指针,指向被操作的节点
			while(prevNode != null && currentNode != null){
				if(currentNode.val == val) {
					prevNode.next = currentNode.next;
					size--;
				} else {
					prevNode = currentNode;
				}
				currentNode = currentNode.next;
			}
		}
	}

 6.获取第index节点的值
遍历找到即可。

	public void getElum(int index) {
		if (index > size) {
			System.out.println("越界");
			return;
		}
		ListNode currentNode = headNode;
		for (int i = 0; i < index; i++) {
			currentNode = currentNode.next;
		}
		int result = currentNode.val;
		System.out.println(result);
	}

7.将第Index个节点的值修改为val
找到第index节点,修改val即可。

	public void update(int index, int val) {
		if (index > size) {
			System.out.println("越界");
			return;
		}
		ListNode currentNode = headNode;
		for (int i = 0; i < index; i++) {
			currentNode = currentNode.next;
		}
		currentNode.val = val;
	}

8.创建一个链表

	// 创建一个链表  1->2
	public void creatLinkList() {
		ListNode node1 = new ListNode();
		node1.val = 2;
		ListNode node2 = new ListNode();
		node2.val = 1;
		node1.next = node2;
		headNode = node1;
		size++;
		size++;
	}

9.按顺序打印链表

	public void display(){
		ListNode current = headNode;
		while(current != null){
			System.out.print(current.val);
			if (current.next != null) {
				System.out.print("->");
			}
			current = current.next;
		}
		System.out.println();
	}


三、最终代码展示(包含测试)

package linkedList;

public class SingleLinkedList {

	//定义节点
	static class ListNode {
		int val; // 链表存储的值
		ListNode next; // 指针,指向下一个节点
		ListNode() {
			
		}
		ListNode(int val) { 
			this.val = val; 
		}
		ListNode(int val, ListNode next) { 
			this.val = val;
			this.next = next; 
		}
	}
	
	int size; // 链表长度
	ListNode headNode; //链表头结点
//	ListNode dummyHead = new ListNode(0);
	public SingleLinkedList() {
		headNode = null;
		size = 0;
	}
	
	//头插法
	public void headInsertion(int val) {
		ListNode newListNode = new ListNode(); // 新建一个对象,即为要插入的节点
		newListNode.val = val; // 对节点存入要插入的值
		if (headNode == null) { //头结点为空即是个空链表,头结点直接指向要插入的节点即可
			headNode = newListNode;
		} else {
			newListNode.next = headNode; // 要插入的节点应放在第一个,所以它的下一个节点指向head
			headNode = newListNode; // 插入后新插入的节点是新的头结点
		}
		size ++;
	}
	
	//头插法(使用虚拟头结点的方法)
//	public void headInsertionVirtual(int val) {
//		ListNode dummyHead = new ListNode(0, this.head);
//		ListNode newListNode = new ListNode();
//		newListNode.val = val;
//		ListNode currentNode = dummyHead;
//		currentNode.val = val;
//		currentNode.next = dummyHead.next;
//		size ++;
//	}
	
	//任意位置插入
	public void insert(int index, int val) {
		if (index > size) {
			System.out.println("越界");
			return;
		}
		ListNode newListNode = new ListNode(); // 存放添加元素的链表节点
		newListNode.val = val;
		if (index == 0) { // 插入到第0位,和头插法相同
			if (headNode == null) {
				headNode = newListNode;
			} else {
				newListNode.next = headNode;
				headNode = newListNode;
			}
			size ++;		
		} else {
			ListNode prevNode = headNode; // 创建一个指向头结点的指针
			for (int i = 0; i < index-1; i++) {
				prevNode = prevNode.next; // 用该指针找到要添加元素位置的前一个
			}
			newListNode.next = prevNode.next; // 添加的节点的next指针指向要添加位置的下一个
			prevNode.next = newListNode; //前一个节点的next指针指向添加的节点
			size ++;
		}
	}
	
	//尾插法
	public void tailInsertion(int val) {
		ListNode newListNode = new ListNode();
		newListNode.val = val; 
		ListNode prevNode = headNode; // 创建一个指向头结点的指针
		for (int i = 0; i < size-1; i++) {
			prevNode = prevNode.next;// 用该指针找到要最后一个节点的前一个节点
		}
		newListNode.next = prevNode.next;
		prevNode.next = newListNode;
		size ++;
	}
	
	//删除第index个元素
	public void deleteByIndex(int index) {
		if (index > size) {
			System.out.println("越界");
			return;
		}
		if (headNode == null) {
			System.out.println("空链表");
		} else {
			if (index == 0) { // 删除第一个元素,直接把头结点指向第二个元素即可
				headNode = headNode.next;
				size --;
			} else {
				ListNode prevNode = headNode; // 创建一个指向头结点的指针
				for (int i = 0; i < index-1; i++) {
					prevNode = prevNode.next; // 用该指针找到要删除元素位置的前一个
				}
				System.out.println("delete:"+prevNode.next.val);
				// 要删除的元素的前一个节点的next指针指向下一个节点,完成删除
				prevNode.next = prevNode.next.next; 
				size --;
			}
		}
	}
	
	//删除val元素
	public void deleteByValue(int val) {
		if (headNode == null) {
			System.out.println("空链表");
		} else {
			while(val == headNode.val){// 如果头结点是要删除的元素
				headNode = headNode.next;
				size --;
			}
			ListNode prevNode = headNode; // 创建指针,指向被操作的节点的前一位
			ListNode currentNode = headNode; // 创建指针,指向被操作的节点
			while(prevNode != null && currentNode != null){
				if(currentNode.val == val) {
					prevNode.next = currentNode.next;
					size--;
				} else {
					prevNode = currentNode;
				}
				currentNode = currentNode.next;
			}
		}
	}
	
	public void getElum(int index) {
		if (index > size) {
			System.out.println("越界");
			return;
		}
		ListNode currentNode = headNode;
		for (int i = 0; i < index; i++) {
			currentNode = currentNode.next;
		}
		int result = currentNode.val;
		System.out.println(result);
	}
	
	public void update(int index, int val) {
		if (index > size) {
			System.out.println("越界");
			return;
		}
		ListNode currentNode = headNode;
		for (int i = 0; i < index; i++) {
			currentNode = currentNode.next;
		}
		currentNode.val = val;
	}
	
	// 创建一个链表  1->2
	public void creatLinkList() {
		ListNode node1 = new ListNode();
		node1.val = 2;
		ListNode node2 = new ListNode();
		node2.val = 1;
		node1.next = node2;
		headNode = node1;
		size++;
		size++;
	}
	
	
	//打印链表
	public void display(){
		ListNode current = headNode;
		while(current != null){
			System.out.print(current.val);
			if (current.next != null) {
				System.out.print("->");
			}
			current = current.next;
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		SingleLinkedList singleLinkedList = new SingleLinkedList();

		singleLinkedList.creatLinkList();
		singleLinkedList.headInsertion(5);
		singleLinkedList.headInsertion(8);
		singleLinkedList.headInsertion(9);
		singleLinkedList.headInsertion(5);
		singleLinkedList.display();
		
		singleLinkedList.insert(0,3);
		singleLinkedList.insert(0,3);
		singleLinkedList.insert(2,3);
		singleLinkedList.insert(2,3);
		singleLinkedList.insert(2,7);
		singleLinkedList.display();
		
		singleLinkedList.tailInsertion(1);
		singleLinkedList.display();
		
		singleLinkedList.deleteByIndex(1);
		singleLinkedList.display();
		
		singleLinkedList.deleteByValue(3);
		singleLinkedList.display();
		singleLinkedList.getElum(0);

		singleLinkedList.update(1, 6);
		singleLinkedList.display();
	}
}

                                     感谢大家的阅读,觉得有所帮助的朋友点点关注点点赞!

  链表类List的源代码如下: import Java.io.*; public class List {  /*用变量来实现表头*/  private Node Head=null;  private Node Tail=null;  private Node Pointer=null;  private int Length=0;  public void deleteAll()  /*清空整个链表*/  {   Head=null;   Tail=null;   Pointer=null;   Length=0;  }  public void reset()  /*链表复位,使第一个结点成为当前结点*/  {   Pointer=null;  }  public boolean isEmpty()  /*判断链表是否为空*/  {   return(Length==0);  }  public boolean isEnd()  /*判断当前结点是否为最后一个结点*/  {   if(Length==0)    throw new Java.lang.NullPointerException();   else if(Length==1)    return true;   else    return(cursor()==Tail);  }  public Object nextNode()  /*返回当前结点的下一个结点的值,并使其成为当前结点*/  {   if(Length==1)    throw new Java.util.NoSuchElementException();   else if(Length==0)    throw new Java.lang.NullPointerException();   else   {    Node temp=cursor();    Pointer=temp;    if(temp!=Tail)     return(temp.next.data);    else     throw new Java.util.NoSuchElementException();   }  }  public Object currentNode()  /*返回当前结点的值*/  {   Node temp=cursor();   return temp.data;  }     public void insert(Object d)  /*在当前结点前插入一个结点,并使其成为当前结点*/  {   Node e=new Node(d);   if(Length==0)   {    Tail=e;    Head=e;   }   else   {    Node temp=cursor();    e.next=temp;    if(Pointer==null)     Head=e;    else     Pointer.next=e;   }   Length++;  }  public int size()  /*返回链表的大小*/  {   return (Length);  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蜜蜂vs码农

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值