1.链表的概念及结构
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。 可以形象的理解,在逻辑上来看,链表就像是一节节火车车厢。
链表的分类:链表的结构有很多种,单向或双向、带头或不带头、循环或不循环。这篇文章就从最简单的链表结构讲起———不带头单向非循环链表(单链表)。
2.单链表模拟实现
为了更好的学习对于单链表的操作。我们自己模拟实现一些基本的功能。
1.准备工作
接口
package List;public interface IList {//头插法void addFirst(int data);//尾插法public void addLast(int data);//任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data);//查找是否包含关键字key是否在单链表当中public boolean contains(int key);//删除第一次出现关键字为key的节点public void remove(int key);//删除所有值为key的节点public void removeAllKey(int key);//得到单链表的长度public int size();//清空public void clear() ;//打印public void display() ;
}
通过实现接口中的抽象方法实现单链表增删查改的实现。
单链表的定义
单链表(SinglyLinkedList)的定义需要定义单个节点ListNode。单个节点有data存储数据,next存储下一个节点的引用。同时单链表还需要一个成员变量head存储单链表的头位置。基于以上的需要可以把ListNode定义为单链表的内部类。
public class SinglyLinkedList {public class ListNode{public int data;public ListNode next;public ListNode(int data) {this.data = data;}}public ListNode head;
}
2.具体接口实现
添加
头插
@Overridepublic void addFirst(int data) {ListNode newnode = new ListNode(data);newnode.next = head;head = newnode;}
尾插
@Overridepublic void addLast(int data) {ListNode newnode = new ListNode(data);//链表为空if(head == null){head = newnode;return;}//链表不为空,找尾尾插ListNode cur = head;while (cur.next != null){cur = cur.next;}cur.next = newnode;}
在index位置插入
private void CheckIndex(int index){int len = this.size();if(index < 0 || index > len){throw new IllegalIndexException("index不合法");}}@Overridepublic void addIndex(int index, int data) {try {CheckIndex(index);ListNode newnode = new ListNode(data);if(index == 0){addFirst(data);}if(index == size()){addLast(data);}ListNode cur = head;while(index - 1 != 0){cur = cur.next;index--;}newnode.next = cur.next;cur.next = newnode;}catch (IllegalIndexException e){e.printStackTrace();}}
删除
删除找到第一个key值
@Overridepublic void remove(int key) {if(head == null){return;}//解决头节点问题if(head.data == key){head = head.next;return;}ListNode cur = head;while(cur.next.data != key){cur = cur.next;}ListNode del = cur.next;cur.next = del.next;}
删除所有等于key的值
@Overridepublic void removeAllKey(int key) {if(head == null){return;}ListNode prev = head;ListNode cur = head.next;while (cur != null){if(cur.data == key){prev.next = cur.next;}else {prev = cur;}cur = cur.next;}//解决头节点data等于key的情况if(head.data == key){head = head.next;}}
查找
@Overridepublic boolean contains(int key) {ListNode cur = head;while (cur != null){if(cur.data == key){return true;}cur = cur.next;}return false;}
得到size
@Overridepublic int size() {int count = 0;ListNode cur = head;while(cur != null){count++;cur = cur.next;}return count ;}
清空
@Overridepublic void clear() {ListNode cur = head;while(cur != null){ListNode ret = cur;cur.next = null;cur = ret.next;}head = null;}
打印
@Overridepublic void display() {ListNode cur = this.head;while(cur != null){System.out.print(cur.data + " ");cur = cur.next;}System.out.println();}
2.链表oj
看这篇文章:单链表oj练习(C语言版)
虽然是C语言完成的,但是做题的思想是一样的。
3.LinkedList的模拟实现
LinkedList是java标准库提供的双向链表的实现。还是一样为了更好的理解并运用,先自己模拟实现一个。
1.准备工作
接口
接口和上面的单链表接口一样。
MyLinkedList的定义
和上面的单链表不同的是ListNode里多一个prev用于存储上一个节点的引用和MyLinkedList多一个成员last存储双向链表的尾。
2.具体接口实现
添加
@Overridepublic void addFirst(int data) {ListNode newnode = new ListNode(data);if(head == null){head = last = newnode;}else {newnode.next = head;head.prev = newnode;head = newnode;}}@Overridepublic void addLast(int data) {ListNode newnode = new ListNode(data);if(head == null){head = last = newnode;}else {last.next = newnode;newnode.prev = last;last = newnode;}}private void CheckIndex(int index){if(index < 0 || index > size()){throw new IllegalIndexException("index位置不合法");}}private ListNode FindIndexnode(int index){ListNode cur = head;while(index-1 > 0){cur = cur.next;index--;}return cur;}@Overridepublic void addIndex(int index, int data) {try {CheckIndex(index);if(index == 0){addFirst(data);}if(index == size()){addLast(data);}ListNode newnode = new ListNode(data);ListNode cur = FindIndexnode(index);newnode.next = cur;cur.prev.next = newnode;newnode.prev = cur.prev;newnode.next = cur;}catch(IllegalIndexException e){e.printStackTrace();}}
删除
@Overridepublic void remove(int key) {ListNode cur = head;while(cur != null){if(cur.data == key){if(cur == head){head = head.next;if(head != null){head.prev = null;}}else {cur.prev.next = cur.next;if (cur.next == null) {last = last.prev;} else {cur.next.prev = cur.prev;}}return;}cur = cur.next;}}@Overridepublic void removeAllKey(int key) {ListNode cur = head;while(cur != null){if(cur.data == key){if(cur == head){head = head.next;if(head != null){head.prev = null;}}else {cur.prev.next = cur.next;if (cur.next == null) {last = last.prev;} else {cur.next.prev = cur.prev;}}}cur = cur.next;}}
查找 打印 得到size
和单链表一样,本质都是遍历链表
清空
@Overridepublic void clear() {ListNode cur = head;while(cur != null){ListNode Curn = cur.next;cur.prev = null;cur.next = null;cur = Curn;}head = last = head;}
4.LinkedList的使用
1.构造
public static void main(String[] args) {// 构造一个空的LinkedListList<Integer> list1 = new LinkedList<>();List<String> list2 = new java.util.ArrayList<>();list2.add("JavaSE");list2.add("JavaWeb");list2.add("JavaEE");// 使用ArrayList构造LinkedListList<String> list3 = new LinkedList<>(list2);
}
2.其他方法