为了表示每个数据元素ai与其直接后继元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需要存储一个指示其直接后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称作指针或链。这两部分信息组成数据元素ai的存储映像,称为结点(Node)
n个结点链接在一起即为线性表的链式存储结构。
单链表
因为此链表的每个节点上都只有一个指针域指向后继结点,所以称为单链表
单链表指定位置添加结点时,首先我们要将目标链结点的next指针指向插入位置之后的链结点,之后还要使插入位置之前的链结点的next指针指向目标链结点。(注意顺序)
单链表删除指定链结点,是通过将目标链结点的上一个链结点的next指针指向目标链结点的下一个链结点,示意图如下:
手写单链表
类结构图
单链表封装类demo
package com.company.datastructure;
public class MySingleLinkedList<E> {
//结点内部类
private class Node<E> {
public E element; //默认初始化为null
private Node<E> next; //默认初始化为null
public Node(){
}
public Node(E element){
this.element = element;
}
}
private Node<E> head; //头结点
private int size; //元素总数
//构造器(初始化链表)
public MySingleLinkedList(){
head = new Node<E>(); //默认初始化为null
}
//增加
/**
* 指定位置插入结点
* @param index 索引
* @param element 结点元素值
*/
public void insert(int index,E element){
rangeCheck(index);
Node<E> newNode = new Node<E>(element);
Node<E> temp = head;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
newNode.next = temp.next; //注意顺序
temp.next = newNode;
size++;
}
/**
* 表头插入元素
* @param element 结点元素值
*/
public void addFirst(E element){
Node<E> newNode = new Node<>(element);
newNode.next = head.next;
head.next = newNode;
size++;
}
/**
* 表尾插入元素
* @param element 结点元素值
*/
public void addLast(E element){
Node<E> newNode = new Node<E>(element);
Node<E> temp = head;
while(temp.next!=null){
temp = temp.next;
}
newNode.next = temp.next; //注意顺序
temp.next = newNode;
size++;
}
//删除
/**
* 删除指定索引处元素(不包含头尾元素)
* @param index 索引
* @return 删除元素值
*/
public E remove(int index){
rangeCheck(index);
Node<E> temp = head;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
E oldElement = temp.next.element;
temp.next = temp.next.next;
size--;
return oldElement;
}
/**
* 从表头删除元素
* @return 删除元素值
*/
public E removeFirst() {
if (size==0){
throw new IndexOutOfBoundsException("链表为空");
}
E oldElement = head.next.element;
head.next = head.next.next;
size--;
return oldElement;
}
/**
* 从表尾删除元素
* @return 删除元素值
*/
public E removeLast(){
if (size==0){
throw new IndexOutOfBoundsException("链表为空");
}
Node<E> temp = head;
while(temp.next.next!=null){
temp = temp.next;
}
E oldElement = temp.next.element;
temp.next = null;
size--;
return oldElement;
}
//修改
/**
* 修改指定索引处元素值
* @param index 索引
* @param element 元素值
* @return 成功返回原元素值
*/
public E set(int index,E element){
rangeCheck(index);
Node<E> temp = head;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
Node<E> oldValue = temp.next;
temp.next.element = element;
return oldValue.element;
}
//查找
/**
* 根据索引返回元素值
* @param index 索引
* @return 索引处元素值
*/
public E get(int index){
rangeCheck(index);
Node<E> temp = head;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp.next.element;
}
/*---------------------------------------------------------------------------------*/
/**
* 获得链表长度
* @return 链表长度
*/
public int size(){
return size;
}
/**
* 链表是否为空
* @return true为空,false不为空
*/
public boolean isEmpty(){
return size==0?true:false;
}
/**
* 清空链表
*/
public void clear(){
Node<E> temp = head;
while(temp.next!=null){
Node<E> next = temp.next;
temp.element = null;
temp.next = null;
temp = next;
}
temp.element = null;
size = 0;
}
/**
* toString方法
* @return 链表内容
*/
public String toString(){
if(size==0){
return "[]";
}else{
Node<E> temp = head.next;
StringBuilder sb = new StringBuilder("[");
while(temp.next!=null){
sb.append(temp.element+",");
temp = temp.next;
}
return sb.append(temp.element).append("]").toString();
}
}
/*---------------------------------------------------------------------*/
/**
* 索引检查
* @param index 索引
*/
private void rangeCheck(int index){
if (index <0|| index >= size){
throw new IndexOutOfBoundsException("索引不合法"+index);
}
}
}
单链表测试demo
package com.company.datastructure;
public class TestMySingleLinkedList {
public static void main(String[] args) {
MySingleLinkedList<Integer> msl = new MySingleLinkedList<>();
msl.addLast(1);
msl.addLast(3);
msl.addLast(4);
msl.insert(1,2);
msl.addFirst(0);
System.out.println(msl.size());
System.out.println(msl);
System.out.println(msl.get(1));
int a = msl.remove(1);
System.out.println(a);
msl.removeFirst();
msl.removeLast();
System.out.println(msl.size());
System.out.println(msl);
}
}