多种链表

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(ireturn 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;

你可能感兴趣的:(数据结构)