链表代码展示

1.node:

package Stack;

public class Node<T>                             //单链表结点类,T指定结点的元素类型
{
    public T data;                               //数据域,存储数据元素
    public Node<T> next;                         //地址域,引用后继结点
    public Node(T data, Node<T> next)            //构造结点,data指定数据元素,next指定后继结点
    {
        this.data = data;                        //T对象引用赋值
        this.next = next;                        //Node<T>对象引用赋值
    }
    public Node()
    {
        this(null, null);
    }
    public String toString()                     //返回结点数据域的描述字符串
    {
        return this.data.toString();
    }
}

2.sInglyList:

package Stack;

//单链表类,实现ADT List<T>声明的方法,T表示数据元素的数据类型
public class SinglyList<T> extends Object implements java.lang.Iterable<T>  //10.2.1,实现可迭代接口
//public class SinglyList<T> extends MyAbstractList<T>       //单链表类,继承抽象列表类//第10章,10.2 实现迭代器 
{
  public Node<T> head;                                   //头指针,指向单链表的头结点
  //注意,head不能是其他权限,因为7.2.2节,图的邻接表中,删除顶点要遍历。2014年8月3日
  
  //(1)构造方法
  public SinglyList()                                    //构造方法,构造空单链表
  {
      this.head = new Node<T>();                         //创建头结点,data和next值均为null
  }
  
  //构造单链表,由values数组提供元素,忽略其中空对象。采用尾插入,单链表元素次序与数组元素次序相同
  public SinglyList(T[] values)
  {
      this();                                            //创建空单链表,只有头结点
      Node<T> rear=this.head;                            //rear指向单链表最后一个结点
      for (int i=0; i<values.length; i++)                //若values.length==0,构造空链表
          if (values[i]!=null)
          {
              rear.next=new Node<T>(values[i],null);     //尾插入,创建结点链入rear结点之后
              rear = rear.next;                          //rear指向新的链尾结点
          }
  }

  public boolean isEmpty()                               //判断单链表是否空,O(1)
  {
      return this.head.next==null;
  }

  //(2)存取
  public T get(int i)                                    //返回第i个元素,0≤i<表长度。若i越界,返回null。O(n)
  {
      Node<T> p=this.head.next;
      for (int j=0; p!=null && j<i; j++)                 //遍历单链表,寻找第i个结点(p指向)
          p = p.next;
      return (i>=0 && p!=null) ? p.data : null;          //若p指向第i个结点,返回其元素值
  }
 
  //【思考题2-5】  
  //设置第i个元素为x,0≤i<n。若i越界,抛出序号越界异常;若x==null,抛出空对象异常。O(n)
  public void set(int i, T x)
  {
      if (x==null)
          throw new NullPointerException("x==null");     //抛出空对象异常
      Node<T> p=this.head.next;
      for (int j=0; p!=null && j<i; j++)                 //遍历寻找第i个结点(p指向)
          p = p.next;
      if (i>=0 && p!=null)
          p.data = x;                                    //p指向第i个结点
      else throw new IndexOutOfBoundsException(i+"");    //抛出序号越界异常
  }     
  
  //返回单链表所有元素的描述字符串,形式为“(,)”。覆盖Object类的toString()方法,O(n)
  public String toString()
  {
      String str=this.getClass().getName()+"(";          //返回类名
//      String str="(";
      for (Node<T> p=this.head.next;  p!=null;  p=p.next)//p遍历单链表
      {   str += p.data.toString();
          if (p.next!=null) 
              str += ",";                                //不是最后一个结点时,加分隔符
      }
      return str+")";                                    //空表返回()
  }

  //【思考题2-5】  
  public int size()                                      //返回单链表长度,O(n)
  {
      int i=0; 
      for (Node<T> p=this.head.next;  p!=null;  p=p.next) //p遍历单链表
          i++;
      return i;
  }
  
  //(3)插入
  //插入x作为第i个元素,x!=null,返回插入结点。
  //对序号i采取容错措施,若i<0,插入x在最前;若i>n,插入x在最后。O(n)
  public Node<T> insert(int i, T x)
  {
      if (x==null)
          throw new NullPointerException("x==null");     //抛出空对象异常
      Node<T> front=this.head;                           //front指向头结点
      for (int j=0;  front.next!=null && j<i;  j++)      //寻找第i-1个或最后一个结点(front指向)
          front = front.next;
      front.next = new Node<T>(x, front.next);           //在front之后插入值为x结点,包括头插入、中间/尾插入
      return front.next;                                 //返回插入结点
  }
  public Node<T> insert(T x)                             //在单链表最后添加x对象,O(n)
  {
      return insert(Integer.MAX_VALUE, x);
                           //调用insert(i,x),用整数最大值指定插入在最后,遍历一次,i必须容错
//      return insert(this.count(), x);                  //需遍历单链表两次,效率较低
  }
    
  //(4)删除
  public T remove(int i)    //删除第i个元素,0≤i<n,返回被删除元素;若i越界,返回null。O(n)
  {
      Node<T> front=this.head;                           //front指向头结点
      for (int j=0;  front.next!=null && j<i;  j++)      //遍历寻找第i-1结点(front指向)
          front = front.next;
      if (i>=0 && front.next!=null)                      //若front的后继结点存在,则删除之
      {
          T old = front.next.data;                       //获得待删除结点引用的对象
          front.next = front.next.next;                  //删除front的后继结点,包括头删除、中间/尾删除
                                                         //由Java虚拟机稍后释放结点占用存储单元
          return old;
      }
      return null;                                       //若i<0或i>表长
//      throw new IndexOutOfBoundsException(i+"");       //抛出序号越界异常
  }

  public void clear()                                    //删除单链表所有元素
  {
      this.head.next=null;                               //Java自动收回所有结点占用的存储空间
  }

  //(5)查找,散列表用
  //功能及参数:返回首个与key相等元素结点,若查找不成功返回null
  //特殊情况:若key为空对象,Java将抛出空对象异常
  //算法及效率:顺序查找,O(n)
  //用于7.2.2节图的邻接表,必须返回结点,因为要求后继结点。2014年8月6日,对其他影响未修改

  //顺序查找关键字为key元素,返回首次出现的元素,若查找不成功返回null
  //key可以只包含关键字数据项,由T类的equals()方法提供比较对象相等的依据
  public Node<T> search(T key) 
  {
      for (Node<T> p=this.head.next;  p!=null;  p=p.next)
          if (key.equals(p.data))                        //执行T类的equals(Object)方法,运行时多态
              return p;
      return null;
  }

  public boolean contains(T key)               //判断是否包含关键字为key元素
  {
      return this.search(key)!=null;                     //以查找结果获得判断结果
  }

  //以下【思考题2-7】  
  //也可【实验题2-10】声明子类实现,互异单链表类
  //尾插入互异元素x,若查找到与x的关键字相同元素,不插入,返回x结点;覆盖。//散列表用
  public Node<T> insertDifferent(T x)
  {
      Node<T> front=this.head, p=front.next;             //front是p的前驱结点
      while (p!=null && !p.data.equals(x))               //顺序查找
      {
          front = p; 
          p = p.next;
      }
      if (p!=null)                                       //查找成功,元素重复,不插入,返回p结点
      {
          System.out.println("x="+x+",元素重复,未插入。");
          return p;
      }
      return front.next = new Node<T>(x,null);           //尾插入值为x结点,返回插入结点
  }
  
  public T remove(T key)             //删除首个与key相等元素结点,返回被删除元素;查找不成功返回null。O(n)散列表用
  {
      Node<T> front=this.head, p=front.next;
      while (p!=null && !key.equals(p.data))             //顺序查找首次出现的与key相等元素
      {
          front = p;                                     //front指向p的前驱结点
          p=p.next;
      }
      if (p!=null)                                       //若查找成功,删除front的后继(p结点)
      {
          front.next = p.next;                           //包括头删除、中间/尾删除
          return p.data;
      }
      return null;
  }
  //思考题:remove(x)方法能否调用search(x)方法定位?为什么?
  //以上实现ADT List,第2章  
  
  //(4)提高单链表操作效率的措施
  
  //【例2.5】  单链表逆转。
  
  //5. 单链表的浅拷贝与深拷贝
  //【思考题2-8】
//不行    public SinglyList(SinglyList<? extends T> list)   //深拷贝构造方法,复制单链表list的所有结点
 //相当于Node<? extends T>,即Node<?>
  
  public SinglyList(SinglyList<T> list)                  //深拷贝构造方法,复制单链表list的所有结点
  {
      this();                                            //创建空单链表,只有头结点
      Node<T> rear=this.head;
      for (Node<T> p=list.head.next;  p!=null;  p=p.next)  //p遍历list单链表
      {
          rear.next = new Node<T>(p.data, null);        //复制结点尾插入到this单链表
          rear = rear.next;                             //指向this单链表尾
      }
  }
  
  public boolean equals(Object obj)            //比较两条单链表是否相等,覆盖Object类的equals(obj)方法
  {
      if (obj == this)
          return true;
      if (!(obj instanceof SinglyList<?>))
          return false;
      Node<T> p=this.head.next;
      Node<T> q=((SinglyList<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;
  }   
  
  //【实验2-7 习题解答】  单链表的迭代方法。 
  //(1)以下4个方法提供迭代遍历单链表方式
  public Node<T> first()                                 //返回单链表第一个元素结点,O(1)
  {
      return this.head.next;                             //若单链表空返回null
  }
  public Node<T> next(Node<T> p)                         //返回p的后继结点,O(1)
  {
      return (this.head.next==null || p==null) ? null : p.next;
  }
  public Node<T> previous(Node<T> p)                     //返回p的前驱结点,O(n)
  {
      if (this.head.next==null || p==null || p==this.head.next)
          return null;
      Node<T> front=this.head.next;
      while (front.next!=p)
          front = front.next;
      return front;
  }
  public Node<T> last()                                  //返回单链表最后一个元素结点,O(n)
  {
      Node<T> p=this.head.next;
      while (p!=null && p.next!=null)
          p = p.next;
      return p;                                          //若单链表空返回null
  }  
  
  
  //【实验2-6】  单链表对子表的操作。    
  //【习题解答例2.1】单链表作为方法参数与返回值问题讨论。
  //在this单链表之后连接list单链表,首尾相接合并成一条单链表;设置list为空单链表,O(n)
  public void concat(SinglyList<T> list)
  {
      Node<T> rear=this.head;
      while (rear.next!=null)                            //寻找this单链表的最后一个结点作为插入位置
          rear = rear.next;
      rear.next = list.head.next;                        //将list链接在this单链表之后,合并两条单链表成一条单链表
      list.head.next=null;                               //设置list为空单链表,否则逻辑错。对引用形式参数的任何修改均作用于实际参数
  }

  public void addAll(SinglyList<T> list)                 //复制list所有结点插入到this单链表之后,集合并,不改变list。
  {
      this.concat(new SinglyList<T>(list));              //先执行单链表深拷贝,再传递对象引用
      //功能同以下。
/*        Node<T> rear=this.head;
      while (rear.next!=null)                            //寻找this单链表的最后一个结点作为插入位置
          rear = rear.next;
      for (Node<T> p=list.head.next;  p!=null;  p=p.next)  //p遍历list单链表
      {
          rear.next = new Node<T>(p.data, null);        //复制结点尾插入到this单链表
          rear = rear.next;                             //指向this单链表尾
      }*/
  }

  //返回复制this和list合并连接的单链表,并集,不改变this和list。
  //说明:只能返回SinglyList<T>,不能返回子类实例,子类如果需要必须覆盖,因此,对子类没有作用。
  public SinglyList<T> union(SinglyList<T> list)
  {
      SinglyList<T> result = new SinglyList<T>(this);   //单链表深拷贝
      result.addAll(list);
      return result;
  }
  
  
  //第10章,10.2 实现迭代器
  public java.util.Iterator<T> iterator()      //返回Java迭代器对象
  {
      return new SinglyIterator();
  }

  private class SinglyIterator implements java.util.Iterator<T> //私有内部类,实现迭代器接口
  {
      Node<T> current=SinglyList.this.head;    //当前结点,初值为外部类单链表头结点
      Node<T> front=null;                      //当前结点的前驱结点

      public boolean hasNext()                 //若有后继元素,返回true
      {
          return this.current!=null && this.current.next!=null;
      }

      public T next()                          //返回后继元素
      {
          if (this.hasNext())
          {
              this.front = this.current;
              this.current = this.current.next;
              return this.current.data;
          }
          else throw new java.util.NoSuchElementException();  //抛出无此元素异常
      }

      public void remove()                     //删除迭代器对象表示的集合当前元素
      {
          if (this.front!=null)
          {
              this.front.next = this.current.next; //删除当前结点
              this.current = this.front;
              this.front=null;                     //设置不能连续删除
          }
          else throw new java.lang.IllegalStateException();//抛出无效状态异常
//          throw new UnsupportedOperationException();     //不支持该操作,抛出异常
      }
  }//内部类结束
  
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
静态链表是一种使用数组实现的链表数据结构。下面是一个简单的静态链表代码示例: ```c #include <stdio.h> #define MAX_SIZE 100 // 定义静态链表的节点结构 typedef struct { int data; int next; // 游标,表示下一个节点在数组中的索引 } Node; // 初始化静态链表 void initStaticList(Node list[]) { for (int i = 0; i < MAX_SIZE - 1; i++) { list[i].next = i + 1; // 设置游标,使得每个节点都指向下一个节点 } list[MAX_SIZE - 1].next = -1; // 设置最后一个节点的游标为-1,表示链表结束 } // 插入节点 void insertNode(Node list[], int data) { int newNodeIndex = list[0].next; // 获取第一个可用节点的索引 if (newNodeIndex != -1) { list[0].next = list[newNodeIndex].next; // 更新第一个可用节点的索引 list[newNodeIndex].data = data; list[newNodeIndex].next = -1; printf("插入节点:%d\n", data); } else { printf("静态链表已满,无法插入节点:%d\n", data); } } // 打印静态链表 void printStaticList(Node list[]) { int currentIndex = list[0].next; // 获取第一个节点的索引 printf("静态链表内容:"); while (currentIndex != -1) { printf("%d ", list[currentIndex].data); currentIndex = list[currentIndex].next; // 更新当前节点的索引 } printf("\n"); } int main() { Node staticList[MAX_SIZE]; initStaticList(staticList); insertNode(staticList, 1); insertNode(staticList, 2); insertNode(staticList, 3); printStaticList(staticList); return 0; } ``` 在上述示例中,我们使用一个静态数组 `staticList` 来实现静态链表。通过初始化函数 `initStaticList`,我们将数组中的每个元素设置为可用节点,并通过游标将它们连接起来。 插入节点的函数 `insertNode` 首先从第一个可用节点中获取一个节点,然后更新第一个可用节点的索引。接着,我们将节点的数据域设置为给定的数据,并将游标设置为-1,表示链表结束。 最后,通过函数 `printStaticList`,我们遍历静态链表并打印出其中的数据。在主函数中,我们示范了插入节点和打印链表的操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值