注:总结自《数据结构》
(1)概念:
单链表属于线性表的一种。
线性表的链式存储结构是用若干地址分散的存储单元存储数据元素,逻辑上相邻的数据元素在物理位置上不一定相邻,必须采用附加信息表示数据元素之间的顺序关系。存储一个数据元素的存储单元至少包含两部分—数据域和地址域。
单链表的特点:
a.有一个位置存放数据元素,有一个指针指向下一个元素,根据某个节点,可以找到数据元素以及它的下一个节点,但是想要找到他的先驱节点就得从头开始遍历,判断某个节点的下一个节点是不是指定的节点。
b.单链表的插入、删除不需要移动位置,只需要修改节点的下一个指向就可以了。时间复杂度是O(1)。
c.单链表查找元素不能像顺序表一样,根据下标查找,只能从头结点开始遍历。时间复杂度是O(n)。
d.转序单链表是从第一个元素开始,将指向下一个节点的指针指向前一个元素,也就是先驱节点。
e.排序单链表的插入就是判断当前插入的节点和已排序的链表中的节点相比,把插入的节点放在第一个比它大的节点的前面。
f.循环双链表是最后一个节点的next指针指向头结点。
g.单链表的深拷贝和浅拷贝和顺序表的性质是一样的。浅拷贝是只对头指针赋值,导致两条单链表的两个头指针指向的是同一个节点。深拷贝是仅复制节点,没有复制对象元素,导致两个节点引用同一个元素对象。深度拷贝是不仅复制所有节点,还复制所有对象元素。
(2)单链表结点:
/**
* @date 2017-6-04
* @author liuffei
* @description 单链表
*/
public class Node<T> {
public T data; //数据域,保存数据元素
public Node<T> next;//地址域,引用后继结点
public Node(T data,Node<T> next){
this.data = data;
this.next = next;
}
public Node(){
this(null, null);
}
}
(3)链表基类
public interface LList<T> {
boolean isEmpty();//判断线性表是否为空
void insert(int i,T t);//插入t作为第i个元素
void set(int i,T t);//设置第i个元素为t
T get(int i);//获得第i个元素
int length();//获得线性表的长度
T remove(int i);//删除第i个元素
void removeAll();//删除全部元素
T search(T key);//搜索首次出现关键字为key的元素
void append(T t);//在线性表尾部追加t元素
}
(4)带头结点的单链表
import gdut.ff.LList;
/**
* @date 2017-06-04
* @author liuffei
* @description 带头结点的单链表
* @param <T>
*/
public class SinglyLinkedList<T> implements LList<T>{
public Node<T> head ;//头指针,指向单链表的头结点
public SinglyLinkedList(){
head = new Node<T>();
}
//深拷贝
public SinglyLinkedList(SinglyLinkedList<T> list){
this();
Node<T> rear = this.head ;
Node<T> p = list.head.next;
while(p != null){
rear.next = new Node<T>(p.data,null);
rear = rear.next;
p = p.next;
}
}
//由指定数组中的多个对象构造单链表。采用尾插入构造单链表
public SinglyLinkedList(T[] element){
this();
Node<T> rear = this.head;
for(int i = 0;i < element.length;i++){
rear.next = new Node<T>(element[i],null);
rear = rear.next;
}
}
//判断单链表是否为空
@Override
public boolean isEmpty() {
return this.head.next == null;
}
//在位置i插入元素t
@Override
public void insert(int i, T t) {
if(t == null){
return;
}
Node<T> p = this.head;
for(int j = 0;j < i && p.next != null ;j++){//定位到第i-1个元素
p = p.next;
}
p.next = new Node<T>(t,p.next);
}
//修改位置i上元素的值
@Override
public void set(int i, T t) {
if(t == null){
return ;
}
Node<T> current = getNode(i);
if(null != current){
current.data = t;
}
}
//拿到位置i的元素,返回结点
public Node<T> getNode(int i){
if(i >= 0){
Node<T> p = this.head.next;
for(int j = 0;j < i && p != null;j++){
p = p.next;
}
if(p != null){
return p;
}
}else{
throw new IndexOutOfBoundsException(i+"");
}
return null;
}
//拿到位置i的元素,返回数值
@Override
public T get(int i) {
Node<T> p = getNode(i);
if(p != null){
return p.data;
}
return null;
}
//线性表的长度
@Override
public int length() {
int len = 0;
Node<T> p = this.head.next;
while(null != p){
len++;
p = p.next;
}
return len;
}
//删除指定位置的元素
@Override
public T remove(int i) {
if( i >= 0){
Node<T> p = this.head;
for(int j = 0;j < i && p.next != null;j++){
p = p.next;
}
if(p.next != null){
T old = p.data;
p.next = p.next.next;
return old;
}
}
return null;
}
//删除全部元素
@Override
public void removeAll() {
this.head.next = null;
}
@Override
public T search(T key) {
return null;
}
//在尾部追加元素
@Override
public void append(T t) {
insert(Integer.MAX_VALUE,t);
}
//打印元素
public String toString(){
Node<T> p = this.head.next;
StringBuffer sb = new StringBuffer("(");
while(p != null){
sb.append(p.data);
sb.append(",");
p = p.next;
}
sb.deleteCharAt(sb.length()-1);
sb.append(")");
return sb.toString();
}
//单链表比较相等
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(!(obj instanceof SinglyLinkedList)){
return false;
}
Node<T> p = this.head.next;
Node<T> q = ((SinglyLinkedList<T>)obj).head.next;
while(p != null && q != null && p.data.equals(q.data)){
p = p.next;
q = q.next;
}
return p == null && q == null;
}
}
(5)求单链表的平均值
/**
* @date 2017-6-4
* @author liuffei
* @description 求线性表的平均值
*/
public class SinglyLinkedList_average {
private static Random random = new Random();
/**
* 创建随机数的单链表
* @param n 随机数的数量
* @return
*/
public static SinglyLinkedList randomSerial(int n){
SinglyLinkedList list = new SinglyLinkedList();
for(int i = 0;i < n;i++){
list.append(random.nextInt(100));
}
return list;
}
/**
* 求线性表的平均值(减去最大值和最小值,单链表长度小于2的不减去最大值和最小值)
* @param list
* @return
*/
public static double average(SinglyLinkedList<Integer> list){
if(list.isEmpty()){
throw new IllegalArgumentException("不能对空单链表计算平均值");
}
Node<Integer> p = list.head;
int min = Integer.MAX_VALUE;//设置最小值为IInteger类型的最大值
int max = Integer.MIN_VALUE;//设置最大值为Integer类型的最小值
int sum = 0;//和
int len = list.length();//长度
while(p.next != null){
p = p.next;
if(p.data < min){
min = p.data;
}
if(p.data > max){
max = p.data;
}
sum += p.data;
}
if(len > 2){
sum = sum - min - max;
len = len - 2;
}
System.out.println("max = " + max);
System.out.println("min = " + min);
double average = (double)sum / len;//求平均值
return average;
}
public static void main(String args[]){
SinglyLinkedList list = randomSerial(10);
System.out.println(list.toString());
System.out.println("average = " + average(list));
SinglyLinkedList list2 = randomSerial(1);
System.out.println(list2.toString());
System.out.println("average = " + average(list2));
}
}
(6)求单链表的逆转
/**
* @date 2017-06-04
* @author liuffei
* @description 单链表转序
*/
public class SinglyLinkedList_reverse {
public static SinglyLinkedList<String> reverse(SinglyLinkedList<String> list){
Node<String> p = list.head.next;
Node<String> next = null;
Node<String> front = null;
while(p != null){
next = p.next;//记住当前节点的下一个节点
p.next = front;//当前节点的下一个节点变成前趋节点
front = p;//前趋节点和当前节点都向后移动一位
p = next;
}
//头指针的后继结点指向最后一个节点
list.head.next = front;
return list;
}
public static void main(String args[]){
String values[] = {"A","B","C","D","E"};
SinglyLinkedList<String> list = new SinglyLinkedList(values);
System.out.println(list.toString());
list = reverse(list);
System.out.println(list.toString());
}
}
(7)排序单链表
/**
* @date 2017-06-04
* @author liuffei
* @description 排序单链表
* @param <T>
*/
public class SortedSinglyLinkedList<T extends Comparable<T>> extends SinglyLinkedList<T> {
//默认构造方法,调用父类默认构造方法
public SortedSinglyLinkedList(){
super();
}
public SortedSinglyLinkedList(T[] element){
super();
if(element != null){
for(int i = 0;i < element.length;i++){
insert(element[i]);
}
}
}
public SortedSinglyLinkedList(SortedSinglyLinkedList<T> list){
super(list);
}
public void insert(T t){
if(t == null){
return;
}
Node<T> front = this.head;
Node<T> p = front.next;
while(p != null && p.data.compareTo(t) < 0){
front = p;
p = p.next;
}
front.next = new Node<T>(t,p);
}
public void remove(T t){
if(t == null){
return;
}
Node<T> front = this.head;
Node<T> p = front.next;
while(p != null && p.data.compareTo(t) < 0){
front = p;
p = p.next;
}
if(p != null && p.data.compareTo(t) == 0){
front.next = p.next;
}
}
public void insert(int i,T t){
throw new UnsupportedOperationException("insert(int i,T x)");
}
public void append(T t){
throw new UnsupportedOperationException("append(T t)");
}
}
(8)单链表解决约瑟夫环问题
public class Josephus_SinglyLinkedList {
public static void remove(SinglyLinkedList list,int distance,int live){
int begin = 0;
while(list.length() > live){
begin = (begin+distance-1)%list.length();
list.remove(begin);
}
}
public static void main(String args[]){
SinglyLinkedList list = new SinglyLinkedList();
list.append("A");
list.append("B");
list.append("C");
list.append("D");
list.append("E");
System.out.println(list.get(3));
System.out.println(list.length());
System.out.println(list.toString());
remove(list,2,1);
System.out.println(list.toString());
}
}
(9)循环单链表
/**
* @date 2017-6-5
* @author liuffei
* @description 循环单链表
* @param <T>
*/
public class CirSinglyLinkedList<T> {
public Node<T> head;
public CirSinglyLinkedList(){
this.head = new Node<T>();
this.head.next = this.head;
}
public boolean isEmpty(){
return this.head.next == this.head;
}
public String toString(){
StringBuffer sb = new StringBuffer("(");
Node<T> p = this.head.next;
while(p != null){
sb.append(p.data);
sb.append(",");
p = p.next;
}
sb.deleteCharAt(sb.length()-1);
sb.append(")");
return sb.toString();
}
}