1. 什么是链表
用一组地址任意的存储单元存放线性表中的数据元素,即逻辑上连续,物理上不一定连续。
在顺序表的链式存储结构中,每个存储的节点不仅包含数据元素本身(称之为数据域),而且还包括此节点的后继节点的地址信息(称之为指针域)。一般地,每个节点可以有一个或多个这样的指针域,如果某个节点中的某个指针域不再需要指向任何节点,则它的值为null
。
2. 什么是单链表
在每个节点中除了包含数据域 (data
域) 外,又设置一个指针域 (next
域),用以指向其后继节点,即每个节点的构成:元素(数据元素的映像) + 指针(指向后继元素的存储位置)。
3. 不带头非循环单链表
这种单链表必须有一个头指针(假设起名叫head
),用以指向单链表中的第一个节点,否则单链表会在内存中丢失。
- 以下是不带头非循环单链表的
Java
语言实现:
package com.Linked;
public interface ILinked {
//头插法
void addFirst(int data);
//尾插法
void addLast(int data);
//任意位置插入,第一个数据节点为0号下标
boolean addIndex(int index, int data);
//查找是否包含关键字key是否在单链表当中
boolean contains(int key);
//删除第一次出现关键字为key的节点
int remove(int key);
//删除所有值为key的节点
void removeAllKey(int key);
//得到单链表的长度
int getLength();
//打印单链表
void display();
//清空单链表以防内存泄漏
void clear();
}
package com.Linked;
public class MySingleListImpl implements ILinked {
//节点类
class Node {
private int data;
private Node next;
public Node(int data) {
this.data = data;
this.next = null;
}
}
private Node head;
public MySingleListImpl() {
//head初始化为0,因为不知道它到底指向哪儿
this.head = null;
}
@Override
public void addFirst(int data) {
Node node = new Node(data);
//如果单链表为空,只需要让head指向node
if (this.head == null) {
this.head = node;
}else {
//链表不为空
node.next = this.head;
this.head = node;
}
}
@Override
public void addLast(int data) {
Node node = new Node(data);
//链表为空时同头插法
if (this.head == null) {
this.head = node;
}else {
Node cur = this.head;
while (cur.next != null) {//找最后一个节点
cur = cur.next;
}
cur.next = node;
}
}
//找index-1位置的节点
public Node searchIndex(int index) {
if (index < 0 || index > getLength()) {
throw new UnsupportedOperationException();
}
int i = 0;
Node cur = this.head;
while (i < index-1) {
cur = cur.next;
i++;
}
return cur;
}
@Override
public boolean addIndex(int index, int data) {
if (index == 0) {
addFirst(data);
return true;
}
if (index == getLength()) {
addLast(data);
return true;
}
Node node = new Node(data);
Node pre = searchIndex(index);
node.next = pre.next;
pre.next = node;
return true;
}
@Override
public boolean contains(int key) {
//单链表为空
if (this.head == null) {
return false;
}
Node cur = this.head;
while (cur != null) {
if (cur.data == key) {
return true;
}
cur = cur.next;
}
return false;
}
//寻找要删除的节点的前驱
public Node searchPre(int key) {
Node cur = this.head;
while (cur.next != null) {
if (cur.next.data == key) {
return cur;
}
cur = cur.next;
}
return null;
}
@Override
public int remove(int key) {
if (this.head == null) {
throw new UnsupportedOperationException("单链表为空,不支持删除");
}
//因为要求返回值为int型,所以定义了一个oldData来记录要删除节点的data域
int oldData = 0;
//searchPre返回值有两种,要么找到了,要么没找到,分情况讨论
Node pre = searchPre(key);
if (pre == null) {
throw new UnsupportedOperationException("链表中没有该节点的前驱");
}
oldData = pre.next.data;
pre.next = pre.next.next;
//如果要删除的是第一个节点,上述两种情况不能覆盖
if (this.head.data == key) {
oldData = this.head.data;
this.head = this.head.next;
return oldData;
}
return oldData;
}
@Override
public void removeAllKey(int key) {
if (this.head == null) {
throw new UnsupportedOperationException("单链表为空,不支持删除");
}
Node pre = this.head;
Node cur = this.head.next;
while (cur != null) {
if (cur.data == key) {
pre.next = cur.next;
cur = cur.next;
}else {
pre = cur;
cur = cur.next;
}
}
if (this.head.data == key) {
this.head = this.head.next;
}
}
@Override
public int getLength() {
if (this.head == null) {
return 0;
}
int count = 0;
Node cur = this.head;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
@Override
public void display() {
Node cur = this.head;
while (cur != null) {
System.out.print(cur.data + " ");
cur = cur.next;
}
System.out.println();
}
@Override
public void clear() {
Node cur = this.head;
while (cur.next != null) {
this.head = cur.next;
cur = cur.next;
}
this.head = null;
}
}
package com.Linked;
public class Test {
public static void main(String[] args) {
MySingleListImpl list = new MySingleListImpl();
list.addFirst(10);
list.addFirst(20);
list.addFirst(30);
list.addLast(10);
list.addLast(20);
list.addLast(30);
System.out.print("原链表:");
list.display();
System.out.println("链表的长度:" + list.getLength());
list.addIndex(3, 99);
System.out.print("添加后的链表:");
list.display();
System.out.println("链表是否包含元素99:" + list.contains(99));
System.out.println("链表是否包含元素100:" + list.contains(100));
list.remove(99);
System.out.print("删除99之后的链表:");
list.display();
list.removeAllKey(20);
System.out.print("删除所有值为20的节点后的链表:");
list.display();
list.clear();
System.out.print("清空后的单链表:");
list.display();
}
}