1:静态链表
用数组描述的链表叫做静态链表。
数组的元素由两个数据域组成:data和cur。数据域data存放数据元素,游标cur存放该元素的后继在数组中的下标。
未被使用的数组元素称为备用链表。
对数组的第一个和最后一个元素做特殊处理,不存数据。第一个元素的cur存放备用链表的第一个结点的下标。最后一个元素的cur存放第一个有数值的元素的下标,相当于单链表中的头结点。当静态链表为空时,最后一个元素的cur为0。
静态链表的插入:
在第i个元素之前插入新的元素e
//从备用链表上取得第一个结点作为待插入的新节点
int j=space[0].cur; //j为空闲分量的下标
space[0].cur=space[j].cur;//把j的下一分量用作备用链表的起点
//插入结点
int k=MAX_SIZE-1; //k为最后一个元素的下标
space[j].data=e;
for(int l=1;l<=i-1;l++){ // 找到第i-1个元素
k=space[k].space;
}
space[j].cur=space[k].cur;//把第i-1个元素的cur赋值给新元素的cur
space[k].cur=j; //把新元素的下标赋给第i-1个元素的cur
静态链表的删除:
删除第i个元素e
//删除结点
int k=MAX_SIZE-1; //k为最后一个元素的下标
for(int l=1;l<=i-1;l++){ //找到第i-1个元素的位置
k=space[k].space;
}
int j=space[k].cur; //j为待删除元素e的下标
space[k].cur=space[j].cur;//删除下标为j的元素
//将下标为j的空闲结点回收到备用链表
space[j].cur=space[0].cur;
space[0].cur=j;
静态链表的优点:在插入和删除操作时,只需要修改游标,不需要移动元素。
静态链表的缺点:没有解决连续存储分配带来的表长难以确定的问题;失去了顺序存储结构随机存取的特性。
2:循环链表
将单链表中终端结点的指针端由空指针改为指向头结点,就是整个单链表形成一个环。这种头尾相接的单链表称为单循环链表,简称循环链表。
循环链表和单链表的主要差异就在于循环的判断条件上:原来是判断p.next是否为空,现在则是判断p.next是否等于头结点。
用终端结点来表示循环链表,则查找开始结点和终端结点都会很方便。
若rear表示终端结点,则rear.next表示头结点,rear.next.next表示开始结点
两个循环链表,终端结点为rearA和rearB,则它们的合并过程为
p=rearA.next //保存A表的头结点为p
rearA.next=rearB.next.next; //将B表的开始节点赋给rearA.next
rearB.next=p; //将原A表的头结点p赋值给rearB.next
循环链表的应用:约瑟夫问题
约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外, 剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
//根据输入的n创建有n个节点的循环链表
public ListNode creatRing(int n){
if(n<0){
return null;
}
ListNode head=new ListNode(1);
ListNode tail=head;
for(int i=2;i<=n;i++){
tail.next=new ListNode(i);
tail=tail.next;
}
tail.next=head;
return head;
}
//根据n求得最后剩余者的编号
public ListNode Josephu(ListNode head,int m){
ListNode cur=head;
ListNode pre=null;
while(cur.next!=cur){
int i=1;
while(i<m){
pre=cur;
cur=cur.next;
i++;
}
pre.next=cur.next;
cur=cur.next;
}
return cur;
}
3:双向链表
双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。
public class doubleListNode {
int data;
doubleListNode pre;
doubleListNode next;
ListNode(int x)
{
data = x;
}
}
在结点p后插入结点s:
//先将s插入到p与p.next之间
s.pre=p;
s.next=p.next;
//再修改p及p.next
p.next.pre=s;
p.next=s;
删除结点p:
p.pre.next=p.next;
p.next.pre=p.pre;