声明
此文章为个人笔记文 ,写的都是个人理解,如有哪里有误,还望大佬们指正 。
链表描述 - 百度百科
链表是一种物理 存储单元 上非连续、非顺序的存储结构 ,数据元素 的逻辑顺序是通过链表中的指针 链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素 的数据域,另一个是存储下一个结点地址的指针 域。 相比于线性表顺序结构 ,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1) 的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn) 和O(1) 。
使用链表结构可以克服数组 链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组 随机读取的优点,同时链表由于增加了结点的指针 域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表 ,双向链表 以及循环链表 。链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的存取和操作。程序语言或面向对象语言,如C,C++和Java依靠易变工具来生成链表。
描述总结
-
结构 链表是一种物理 存储单元 上非连续、非顺序的存储结构 。 -
组成 链表由一系列结点(链表中每一个元素称为结点)组成。 -
链表类型 单向链表、双向链表、循环链表
单向链表实现
单向链表结构
单向链表的增删查改操作
具体功能实现方法如下图:
Linked 类准备
public class Linked<T> {
private Node head;
@Override
public String toString() {
StringBuffer text = new StringBuffer();
Node pNode = this.head;
while (pNode != null) {
text.append(",").append(pNode.data);
pNode = pNode.next;
}
if (text.length() > 0) {
text.deleteCharAt(0);
}
return "Linked[" + text.toString() +']';
}
class Node{
T data;
Node next;
public Node(T data) {
this(data, null);
}
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
}
}
新增操作
addHead(T data) 新增为头节点
public boolean addHead (T data) {
Node newNode = new Node(data);
newNode.next = head;
head = newNode;
return true;
}
add(int index, T data) 在指定的位置新增节点
public boolean add (int index, T data) {
if (index == 0) {
return this.addHead(data);
}
Node frontNode = this.head;
for (int i = 1; i < index; i++) {
frontNode = frontNode.next;
if (frontNode == null) {
return false;
}
}
Node nextNode = frontNode.next;
Node newNode = new Node(data);
frontNode.next = newNode;
newNode.next = nextNode;
return true;
}
addLast(T data) 新增为最后一个节点(尾节点)
public boolean addLast (T data) {
if (this.head == null) {
return this.addHead(data);
}
Node lastNode = this.head;
while (lastNode != null) {
if (lastNode.next == null) {
break;
}
lastNode = lastNode.next;
}
lastNode.next = new Node(data);
return true;
}
查询操作
getHead(T data) 获取头节点的元素数据
public T getHead() {
return this.isEmpty() ? null : this.head.data;
}
get(int index, T data) 获取指定位置节点的元素数据
public T get(int index) {
if (index == 0) {
return this.getHead();
}
Node pNode = this.head;
for (int i = 1; i <= index; i++) {
pNode = pNode.next;
if (pNode == null) {
return null;
}
}
return pNode.data;
}
getLast(T data) 获取最后一个节点的元素数据
public T getLast() {
if (this.isEmpty()) {
return null;
}
Node lastNode = this.head;
while (lastNode != null) {
if (lastNode.next == null) {
break;
}
lastNode = lastNode.next;
}
return lastNode.data;
}
删除操作
removeHead() 删除头节点
public boolean removeHead() {
if (this.isEmpty()) {
return false;
}
this.head = this.head.next;
return true;
}
remove(int index) 删除指定位置的节点
public boolean remove(int index) {
if (index == 0) {
return this.removeHead();
}
Node frontNode = this.head;
for (int i = 1; i < index; i++) {
frontNode = frontNode.next;
if (frontNode == null) {
return false;
}
}
Node next = frontNode.next;
frontNode.next = next.next;
return true;
}
remove(T data) 根据元素删除节点
public boolean remove (T data) {
if (this.isEmpty()) {
return false;
}
if (this.head.data.equals(data)) {
return this.removeHead();
}
Node frontNode = this.head;
Node pNode = frontNode.next;
while (pNode != null) {
if (pNode.data.equals(data)) {
frontNode.next = pNode.next;
return true;
}
frontNode = pNode;
pNode = pNode.next;
}
return false;
}
removeLast() 删除最后一个节点(尾节点)
public boolean removeLast() {
if (this.isEmpty()) {
return false;
}
Node frontNode = this.head;
Node pNode = frontNode.next;
while (pNode != null) {
pNode = pNode.next;
if (pNode != null) {
frontNode = frontNode.next;
}
}
frontNode.next = null;
return true;
}
修改操作
setHead(T data) 修改头节点元素数据
public boolean setHead (T data) {
if (this.isEmpty()) {
return false;
}
head.data = data;
return true;
}
set(int index, T data) 修改指定节点元素数据
public boolean set (int index, T data) {
if (index == 0) {
return this.setHead(data);
}
Node pNode = this.head;
for (int i = 1; i <= index; i++) {
pNode = pNode.next;
if (pNode == null) {
return false;
}
}
pNode.data = data;
return true;
}
setLast(T data)修改最后一个节点(尾节点)元素数据
public boolean setLast (T data) {
if (this.isEmpty()) {
return false;
}
Node lastNode = this.head;
while (lastNode.next != null) {
lastNode = lastNode.next;
}
lastNode.data = data;
return true;
}
其他操作
contains(T data) 判断链表是否包含对应的元素数据
public boolean contains(T data) {
if (this.isEmpty()) {
return false;
}
Node pNode = this.head;
while (pNode != null) {
if (pNode.data.equals(data)) {
return true;
}
pNode = pNode.next;
}
return false;
}
isEmpty() 判断链表是否为空
public boolean isEmpty() {
return this.head == null;
}
测试
代码
public class LinkedTest {
public static void main(String[] args) {
Linked<Integer> intLinked = new Linked<>();
System.out.println("----------------- 测试 链表新增操作start -----------------");
intLinked.addHead(-1);
System.out.println("空链表时 新增头节点 intLinked.addHead(-1) -> " + intLinked);
intLinked.add(0, 1);
System.out.println("新增节点位置为0 -> 新增头节点 intLinked.add(0, 1) -> " + intLinked);
intLinked.addHead(0);
System.out.println("试链表不为时 新增头节点 intLinked.addHead(0) -> " + intLinked);
intLinked.addLast(2);
System.out.println("新增尾节点 intLinked.addLast(2) -> " + intLinked);
System.out.println("----------------- 测试 链表新增操作end -----------------\n");
System.out.println("----------------- 测试 链表查询操作start -----------------");
intLinked.add(3, 3);
intLinked.add(4, 4);
System.out.println("新增指定位置节点 intLinked.add(3, 3);intLinked.add(4, 4); -> " + intLinked);
System.out.println("获取头结点元素数据 intLinked.getHead() -> " + intLinked.getHead());
System.out.println("获取指定位置结点元素数据 intLinked.get(1) -> " + intLinked.get(1));
System.out.println("获取指定位置结点元素数据(不存在的节点) intLinked.get(9) -> " + intLinked.get(9));
System.out.println("获取尾结点元素数据 intLinked.getLast() -> " + intLinked.getLast());
System.out.println("----------------- 测试 链表查询操作end -----------------\n");
System.out.println("----------------- 测试 链表删除操作start -----------------");
System.out.println("删除头节点 intLinked.removeHead() -> " + intLinked.removeHead() + "; 链表: " + intLinked);
System.out.println("删除指定位置节点 intLinked.remove(1) -> " + intLinked.remove(1) + "; 链表: " + intLinked);
System.out.println("删除指定位置节点(不存在的节点) intLinked.remove(9) -> " + intLinked.remove(9) + "; 链表: " + intLinked);
System.out.println("删除指定元素节点 intLinked.remove(new Integer(3)) -> " + intLinked.remove(new Integer(3)) + "; 链表: " + intLinked);
System.out.println("删除尾节点 intLinked.removeLast() -> " + intLinked.removeLast() + "; 链表: " + intLinked);
System.out.println("----------------- 测试 链表删除操作end -----------------\n");
System.out.println("----------------- 测试 链表修改操作start -----------------");
System.out.println("修改头节点 intLinked.setHead(-2) -> " + intLinked.setHead(-2)+ "; 链表: " + intLinked);
System.out.println("修改指定位置节点 intLinked.set(1, 0) -> " + intLinked.set(1, 0) + "; 链表: " + intLinked);
System.out.println("修改指定位置节点(不存在的节点) intLinked.set(9, 8) -> " + intLinked.set(9, 8) + "; 链表: " + intLinked);
System.out.println("修改尾节点 intLinked.setLast(666) -> " + intLinked.setLast(666) + "; 链表: " + intLinked);
System.out.println("----------------- 测试 链表修改操作end -----------------\n");
System.out.println("----------------- 测试 链表其他操作start -----------------");
System.out.println("链表是否包含该元素 intLinked.contains(666) -> " + intLinked.contains(666) + "; 链表: " + intLinked);
System.out.println("链表是否包含该元素(不存在的元素) intLinked.contains(777) -> " + intLinked.contains(7777) + "; 链表: " + intLinked);
Linked<String> strLinked = new Linked<>();
System.out.println("链表是否为空 strLinked.isEmpty() -> " + strLinked.isEmpty() + "; 链表: " + strLinked);
strLinked.add(0, "Hello");
System.out.println("链表是否为空(不为空) strLinked.isEmpty() -> " + strLinked.isEmpty() + "; 链表: " + strLinked);
System.out.println("----------------- 测试 链表其他操作end -----------------");
}
}
测试结果
----------------- 测试 链表新增操作start -----------------
空链表时 新增头节点 intLinked.addHead(-1) -> Linked[-1]
新增节点位置为0 -> 新增头节点 intLinked.add(0, 1) -> Linked[1,-1]
试链表不为时 新增头节点 intLinked.addHead(0) -> Linked[0,1,-1]
新增尾节点 intLinked.addLast(2) -> Linked[0,1,-1,2]
----------------- 测试 链表新增操作end -----------------
----------------- 测试 链表查询操作start -----------------
新增指定位置节点 intLinked.add(3, 3);intLinked.add(4, 4); -> Linked[0,1,-1,3,4,2]
获取头结点元素数据 intLinked.getHead() -> 0
获取指定位置结点元素数据 intLinked.get(1) -> 1
获取指定位置结点元素数据(不存在的节点) intLinked.get(9) -> null
获取尾结点元素数据 intLinked.getLast() -> 2
----------------- 测试 链表查询操作end -----------------
----------------- 测试 链表删除操作start -----------------
删除头节点 intLinked.removeHead() -> true; 链表: Linked[1,-1,3,4,2]
删除指定位置节点 intLinked.remove(1) -> true; 链表: Linked[1,3,4,2]
删除指定位置节点(不存在的节点) intLinked.remove(9) -> false; 链表: Linked[1,3,4,2]
删除指定元素节点 intLinked.remove(new Integer(3)) -> true; 链表: Linked[1,4,2]
删除尾节点 intLinked.removeLast() -> true; 链表: Linked[1,4]
----------------- 测试 链表删除操作end -----------------
----------------- 测试 链表修改操作start -----------------
修改头节点 intLinked.setHead(-2) -> true; 链表: Linked[-2,4]
修改指定位置节点 intLinked.set(1, 0) -> true; 链表: Linked[-2,0]
修改指定位置节点(不存在的节点) intLinked.set(9, 8) -> false; 链表: Linked[-2,0]
修改尾节点 intLinked.setLast(666) -> true; 链表: Linked[-2,666]
----------------- 测试 链表修改操作end -----------------
----------------- 测试 链表其他操作start -----------------
链表是否包含该元素 intLinked.contains(666) -> true; 链表: Linked[-2,666]
链表是否包含该元素(不存在的元素) intLinked.contains(777) -> false; 链表: Linked[-2,666]
链表是否为空 strLinked.isEmpty() -> true; 链表: Linked[]
链表是否为空(不为空) strLinked.isEmpty() -> false; 链表: Linked[Hello]
----------------- 测试 链表其他操作end -----------------
单向链表实现全部代码
public class Linked<T> {
private Node head;
public boolean addHead (T data) {
Node newNode = new Node(data);
newNode.next = head;
head = newNode;
return true;
}
public boolean add (int index, T data) {
if (index == 0) {
return this.addHead(data);
}
Node frontNode = this.head;
for (int i = 1; i < index; i++) {
frontNode = frontNode.next;
if (frontNode == null) {
return false;
}
}
Node nextNode = frontNode.next;
Node newNode = new Node(data);
frontNode.next = newNode;
newNode.next = nextNode;
return true;
}
public boolean addLast (T data) {
if (this.head == null) {
return this.addHead(data);
}
Node lastNode = this.head;
while (lastNode != null) {
if (lastNode.next == null) {
break;
}
lastNode = lastNode.next;
}
lastNode.next = new Node(data);
return true;
}
public T getHead() {
return this.isEmpty() ? null : this.head.data;
}
public T get(int index) {
if (index == 0) {
return this.getHead();
}
Node pNode = this.head;
for (int i = 1; i <= index; i++) {
pNode = pNode.next;
if (pNode == null) {
return null;
}
}
return pNode.data;
}
public T getLast() {
if (this.isEmpty()) {
return null;
}
Node lastNode = this.head;
while (lastNode != null) {
if (lastNode.next == null) {
break;
}
lastNode = lastNode.next;
}
return lastNode.data;
}
public boolean removeHead() {
if (this.isEmpty()) {
return false;
}
this.head = this.head.next;
return true;
}
public boolean remove(int index) {
if (index == 0) {
return this.removeHead();
}
Node frontNode = this.head;
for (int i = 1; i < index; i++) {
frontNode = frontNode.next;
if (frontNode == null) {
return false;
}
}
Node next = frontNode.next;
frontNode.next = next.next;
return true;
}
public boolean remove (T data) {
if (this.isEmpty()) {
return false;
}
if (this.head.data.equals(data)) {
return this.removeHead();
}
Node frontNode = this.head;
Node pNode = frontNode.next;
while (pNode != null) {
if (pNode.data.equals(data)) {
frontNode.next = pNode.next;
return true;
}
frontNode = pNode;
pNode = pNode.next;
}
return false;
}
public boolean removeLast() {
if (this.isEmpty()) {
return false;
}
Node frontNode = this.head;
Node pNode = frontNode.next;
while (pNode != null) {
pNode = pNode.next;
if (pNode != null) {
frontNode = frontNode.next;
}
}
frontNode.next = null;
return true;
}
public boolean setHead (T data) {
if (this.isEmpty()) {
return false;
}
head.data = data;
return true;
}
public boolean set (int index, T data) {
if (index == 0) {
return this.setHead(data);
}
Node pNode = this.head;
for (int i = 1; i <= index; i++) {
pNode = pNode.next;
if (pNode == null) {
return false;
}
}
pNode.data = data;
return true;
}
public boolean setLast (T data) {
if (this.isEmpty()) {
return false;
}
Node lastNode = this.head;
while (lastNode.next != null) {
lastNode = lastNode.next;
}
lastNode.data = data;
return true;
}
public boolean contains(T data) {
if (this.isEmpty()) {
return false;
}
Node pNode = this.head;
while (pNode != null) {
if (pNode.data.equals(data)) {
return true;
}
pNode = pNode.next;
}
return false;
}
public boolean isEmpty() {
return this.head == null;
}
@Override
public String toString() {
StringBuffer text = new StringBuffer();
Node pNode = this.head;
while (pNode != null) {
text.append(",").append(pNode.data);
pNode = pNode.next;
}
if (text.length() > 0) {
text.deleteCharAt(0);
}
return "Linked[" + text.toString() +']';
}
class Node{
T data;
Node next;
public Node(T data) {
this(data, null);
}
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
}
}
|