单链表是通过指向后继节点的指针把他的一串节点链接成一个链。以线性表中的第一个数据元素的存储地址称作线性表的头指针,一个单链表就是由一个头指针来唯一标识它。单链表一般有两种表达形式,一种是带头节点的单链表,另一种是不带头节点的单链表,下面我们对单链表的描述则是带头节点的单链表。
首先需要一个节点类,代码如下:
public class Node {
public Object data;//存放节点值
public Node next;//后继节点的引用
public Node() {
this(null,null);
}
public Node(Object data) {
this(data,null);
}
public Node(Object data,Node next) {
this.data = data;
this.next = next;
}
}
接下来对单链表进行描述,首先,需要定义一个头指针来标识它,在进行初始化时需要对头指针进行初始化,指向一个数据,后继节点为空的节点,该节点为头节点。然后实现一些基本功能,代码如下:
import java.util.Scanner;
public class LinkList {
public Node head;//单链表的头指针
public LinkList() {
head = new Node();
}
public LinkList(int n,boolean Order) throws Exception {//构造一个长度为n的单链表
this();
if(Order) {
create1(n);
} else {
create2(n);
}
}
//尾插法
private void create1(int n) throws Exception {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
System.out.println("请输入"+n+"个元素");
for(int i = 0; i < n; i++) {
Object sc = input.next();
insert(length(),sc);
}
}
//头插法
private void create2(int n) throws Exception {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
System.out.println("请输入"+n+"个元素");
for(int i = 0; i < n; i++) {
Object sc = input.next();
insert(0,sc);
}
}
//清除链表中元素
public void clear() {
// TODO Auto-generated method stub
head.data = null;
head.next = null;
}
//判断是否为空
public boolean isEmpty() {
// TODO Auto-generated method stub
return head.next == null;
}
//带头节点的单链表长度
public int length() {
// TODO Auto-generated method stub
Node p = head.next;
int length = 0;
while(p != null) {
p = p.next;
++length;
}
return length;
}
//取得下标为i的元素
public Object get(int i) throws Exception {
// TODO Auto-generated method stub
Node p = head.next;
int j = 0;
while(p != null && j < i) {
p = p.next;
++j;
}
if(j > i || p == null) {
throw new Exception("第"+i+"个元素不存在");
}
return p.data;
}
//在i位置插入x
public void insert(int i, Object x) throws Exception {
// TODO Auto-generated method stub
Node p = head;
Node s = new Node(x);
int j = -1;
while(p != null && j < i-1) {
p = p.next;
++j;
}
if (j > i-1 || p == null) {
throw new Exception("插入位置不合法");
}
s.next = p.next;
p.next = s;
}
//删除位置为i的元素
public void remove(int i) throws Exception {
// TODO Auto-generated method stub
Node p = head;
int j = -1;
while(p.next != null && j < i-1) {
p = p.next;
++j;
}
if(p.next == null || j > i - 1) {
throw new Exception("删除位置不合适");
}
p.next = p.next.next;
}
//x在链表首次出现的位置
public int indexOf(Object x) throws Exception {
// TODO Auto-generated method stub
Node p = head.next;
int i = 0;
while(p != null && !p.data.equals(x)) {
p = p.next;
++i;
}
if(p == null) {
throw new Exception("没有该值");
}
return i;
}
//输出链表中的元素
public void display() {
// TODO Auto-generated method stub
Node p = head.next;
while(p != null) {
System.out.print(p.data+" ");
p = p.next;
}
System.out.println();
}
//去掉相同的节点
public void deleteRepeat() throws Exception {
Node p = head.next;
Node q;
while(p != null) {
int Order = indexOf(p.data);
q = p.next;
while (q != null) {
if(p.data.equals(q.data)) {
remove(++Order);
} else {
Order++;
}
q = q.next;
}
p = p.next;
}
}
//两个链表合并成一个链表
public LinkList combineLink(LinkList l1,LinkList l2) {
Node p = l1.head;
Node q = l2.head.next;
while(p.next != null) {
p = p.next;
}
p.next = q;
return l1;
}
}
对于插入操作,在位置为i的地方插入一个数据,需要找到他的前驱节点i-1。查看,删除操作也是一样。
其实单链表的操作就在于对指针的操作,指针就是一个对象的地址,通过指针可以找到这个对象,理解了指针就可以很容易的理解链表了。