算法(04):链表

本文介绍了链表这一数据结构的基本概念,包括其相对于数组的优势与局限性,并通过约瑟芬问题和链表反转等实例展示了链表的实际操作方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  链表是另外一种基本的数据结构,如果我们要逐个的顺序的遍历数据项集合,那么就可以把数据项组织成链表的形式。链表的每一项包括了我们需要到达另一项的信息。

  链表是数据项的集合,一个结点中除了存放数据项之外,还要包括指向结点的指针。

  链表相对于数组的主要优点在于给我们提供了重新有效的组织数据项的能力,但是,这种便利也牺牲了快速访问任意项数据的能力,因为到达链表中数据项的唯一方法就是沿着链表的头指针往下找。

  首先,我们要知道,我们是通过对结点的引用来定义结点的;而且,链表也可以指向自身,所以,链表也可以是一种循环结构。

  一般来说,我们把链表看成是一个数据项集合顺序排列的数据结构:从一个给定的结点出发,我们认为它的数据项是数据序列的第一项。然后我们沿着它的指针到达另一个数据项,就是序列的第二项,等等。因为链表是可以循环的,所以序列可以是无限的。链表的最后一个结点的指针可以采用以下几种方式:

  • 不指向任何结点的空指针
  • 不含任何数据项的哑结点
  • 指回第一个结点,使链表成为循环链表

  在java中,我们把对象作为结点,如

class Node{
 Object item;
 Node next;
 Node(Object o)
{
  item
=o;
  next
=null;
 }

}


  每个结点由一个数据项和对结点的引用构成。也就是说,我们把指针实现为对结点的引用。

  我们可以从链表中移走任何数据项,把链表的长度减1

  t=x.next;x.next=t.next;

  但是在我们使用x.next=t.next语句从链表中移走结点时,我们可能再也访问不到它了。


我们也可以在链表的任何位置插入一个结点,把链表的长度加1

t.next=x.next;x.next=t;

  我们先来看一个使用链表的简单例子,我们想象有N个人围成一圈,他们想选出一位领袖,每隔M-1个人就去掉一个人(消去第M个人),然后看看最后剩下的是谁?这个问题又叫做约瑟芬问题。

class Josephus{
 
static class Node{
  
int val;
  Node next;
  Node(
int v){
   val
=v;
  }

 }

 
public static void main(String[] args){
  
int N=Integer.parseInt(args[0]);
  
int M=Integer.parseInt(args[1]);
  Node t
=new Node(1);
  Node x
=t;
  
for(int i=2;i<=N;i++)
   x
=(x.next=new Node(i));
  x.next
=t;
  
while(x!=x.next){
   
for(int i=1;i<M;i++)
    x
=x.next;
   x.next
=x.next.next;
  }

  System.out.println(
"Survivor is "+ x.val);
 }

}


  我们使用循环链表直接模拟选举过程,每隔M-1个元素,就把第M个元素删除,直到只剩下一个结点(指向自身)。

  我们最常用的对链表的操作是遍历链表,除了使用while语句外,我们还可以使用:

  for(Node t=x;t!=null;t=t.next)t.val;

  我们再来看一个较为复杂的链表例子,要求把传入的链表反转过来,即返回的链表是指向最后一个结点的指针,最后一个结点再指向倒数第二个结点,以此类推。

static Node reverse(Node x){
 Node t,y
=x,r=null;
 
while(y!=null){
  t
=y.next;
  y.next
=r;
  r
=y;
  y
=t;
 }

 
return r;
}


 这里我们使用r来指向已经被处理过的链表,用y指向未处理部分。我们在t中一个跟在y后的结点的指针,然后把y的指针指向r,再把r移动到y,y移动到t。

  我们可以看出使用数组和链表的差异。如果我们使用链表来解决埃拉托色尼塞问题,程序的开销会很大,因为数组可以快速的访问数组中的任何位置;同理,如果使用数组解决约瑟芬问题,那么就需要使用二维数组,同样程序的开销会变得不可以接受。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值