链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O⑴。
3.实现基本方法
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。在计算机科学中,链表作为一种基础的数据结构可以用来生成其它类型的数据结构。链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接("links")。
链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。
链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
1.定义链表节点
package LinkList;
public class ListNode {
private Object data;
private ListNode next;
//无参数时的构造方法
public ListNode()
{
this(null, null);
}
//带一个参数的构造方法
public ListNode(Object data)
{
this(data, null);
}
//带两个参数的构造方法
public ListNode(Object data, ListNode next)
{
this.data = data;
this.next = next;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
2.接口定义方法(这里就是感觉功能显示得比较清楚)
public interface List {
public void clear();
public boolean isEmpty();
public int length();
public Object get(int i) throws Exception;
public void insert(int i, Object x) throws Exception;
public void remove(int i) throws Exception;
public int indexOf(Object x);
public void display();
}
3.实现基本方法
/**
*单链表只需一个头指针就能唯一的标示它,所以单链表类的成员变量只需设置一个头指针即可
*
*/
public class LinkList implements List
{
//单链表的头指针
private ListNode head;
public LinkList()
{
//初始化头结点
head = new ListNode();
}
public void create(int n) throws Exception
{
//构造用于输入对象
Scanner sc = new Scanner(System.in);
for(int j = 0; j < n; j++)
{
//生成新结点,插入到表尾
insert(length(), sc.next());
}
}
// 将一个已经存在的带头结点单链表置为空表
public void clear()
{
ListNode saveNode;
while(head!=null){
saveNode=head.getNext();
head=null;
head=saveNode;
}
}
// 判断带头结点的单链表是否为空
public boolean isEmpty()
{
return head.getNext() == null;
}
// 求带头结点的单链表的长度
public int length()
{
ListNode p = head;
int lenth = 0;
while(p != null)
{
p = p.getNext();
++lenth;
}
return lenth;
}
/*
* 读取带头结点的单链表中的第i个结点
*
* 时间复杂度为O(n)
*/
public Object get(int i) throws Exception
{
// 初始化,p指向首结点,j为计数器
ListNode p = head.getNext();
int j = 0;
// 从首结点开始向后查找,直到p指向第i个结点或p为空
while (p != null && j < i)
{
// 指向后继结点
p = p.getNext();
// 极速器加1
++j;
}
// i小于0或者大于表长减1
if (j > i || p == null)
{
// 抛出异常
throw new Exception("第" + i + "个元素不存在");
}
// 返回结点p的数据域的值
return p.getData();
}
/*
* 在带头结点的单链表中的第i个结点之前插入一个值为x的新结点
*
* 时间复杂度为O(n)
*/
public void insert(int position, Object x) throws Exception
{
ListNode insertNode=new ListNode(x);
int size=length();
if(position<0||position>size){
System.out.println("插入位置有误");
}
if(position == 0){
ListNode current=head;
insertNode.setNext(current);
head=insertNode;
}else{
ListNode previousNode=head;
int count=1;
while(count<position){
previousNode=previousNode.getNext();
count++;
}
ListNode currentNode=previousNode.getNext();
insertNode.setNext(currentNode);
previousNode.setNext(insertNode);
}
}
/*
* 删除单链表中的第i个结点
*
* 时间复杂度为O(n)
*/
public void remove(int position) throws Exception
{
int size=length();
if(position>size+1||position<0){
System.out.println("删除位置有误");
}
if(position== 1){
ListNode currentNode=head.getNext();
head=null;
head=currentNode;
}else{
ListNode preNode=head;
int count=0;
while(count<position){
preNode=preNode.getNext();
count++;
}
ListNode currentNode=preNode.getNext();
preNode.setNext(currentNode.getNext());
currentNode=null;
}
}
/*
* 在单链表中查找值为x的结点
*
* 时间复杂度为O(n)
*/
public int indexOf(Object x)
{
// 初始化,p指向首结点,j为计数器
ListNode p = head.getNext();
int j = 0;
// 下面从单链表中的首结点开始查找,直到p.getData()为x或到达单链表的表尾
while (p != null && !p.getData().equals(x))
{
// 指向下一个结点
p = p.getNext();
// 计数器加1
++j;
}
// 若p指向单链表中的某个结点,返回值为x的结点在单链表中的位置
if (p != null)
{
return j;
} else
{
// 值为x的结点不在链表中
return -1;
}
}
// 输出单链表中的所有结点
public void display()
{
//取出带头结点的单链表中的首结点
ListNode p = head.getNext();
while(p != null)
{
//输出结点的值
System.out.print(p.getData() + " ");
p = p.getNext();
}
System.out.println();
}
}