赞
踩
一、链表
链表(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();
- }
- }
-
感谢大家的阅读,觉得有所帮助的朋友点点关注点点赞!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。