多种链表

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;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值