单链表

单链表

  1. 单链表结点
//单链表结点类

public class Node<T>                             //单链表结点类,T指定结点的元素类型
{
    public T data;                               //数据域,保存数据元素
    public Node<T> next;                         //地址域,引用后继结点

    public Node(T data, Node<T> next)            //构造结点,data指定数据元素,next指定后继结点
    {
        this.data = data;
        this.next = next;
    }
    public Node()
    {
        this(null, null);
    }

    //4、Node类可声明以下方法:
    public String toString()                     //返回结点元素值对应的字符串
    {
        return this.data.toString();
    }    
    public boolean equals(Object obj)            //比较两个结点值是否相等,覆盖Object类的equals(obj)方法
    {
        return obj==this || obj instanceof Node && this.data.equals(((Node<T>)obj).data);
    }    
}

/*问题讨论
1、  当一个类没有声明构造方法时,Java提供默认构造方法。例如
    public Node()                                  //提供默认构造方法
    {
        super();                                   //默认调用语句
    }
          当一个类声明了构造方法时,Java不再提供默认构造方法。
例如,当Node类声明了Node(T data, Node<T> next)构造方法时,Java不再提供默认构造方法Node()。
如果Node类需要Node()构造方法,必须自己声明。

2、  Java方法参数没有默认值。例如,Node类可以声明以下构造方法
    public Node(T data)
    {
        this(data, null);
    }
    但不能将Node(T data, Node<T> next)构造方法声明为如下形式:
    public Node(T data, Node<T> next=null)
    
3、Java不提供默认拷贝构造方法。
  Node类不需要拷贝构造方法。若拷贝构造方法以下,复制p引用的结点,
    public Node(Node<T> p)            //拷贝构造方法
    {
        this(p.data, p.next); 
    }
相当于
    public Node(Node<T> p)
    {
        this.data = p.data;
        this.next = p.next;        //将p结点作为当前结结点的后继结点,含义不对了
    }
    
5、不能声明如下,比较结点值大小
public class Node<T> implements Comparable<Node<T>>   //单链表结点类
{
    public int compareTo(Node<T> p)                  //比较相等,比较大小
    {
        return this.data.compareTo(p.data);
    }
}
排序单链表应该要求比较T对象大小,不能要求比较结点大小。
*/ 

2、带头结点的单链表类,实现线性表接口

//public class SinglyLinkedList<T> implements LList<T>     //2.3   线性表的链式表示和实现
public class SinglyLinkedList<T> extends AbstractLList<T> implements LList<T>//第10章,10.2 实现迭代器 
{
    public Node<T> head;                              //头指针,指向单链表的头结点

    public SinglyLinkedList()                         //默认构造方法,构造空单链表
    {
        this.head = new Node<T>();                    //创建头结点,data和next值均为null
    }
    
    //由指定数组中的多个对象构造单链表。采用尾插入构造单链表
    //若element==null,Java将抛出空对象异常;若element.length==0,构造空链表
    public SinglyLinkedList(T[] element)
    {
        this();                                       //创建空单链表,只有头结点
        Node<T> rear=this.head;                       //rear指向单链表最后一个结点
        for (int i=0; i<element.length; i++)          //若element==null,抛出空对象异常
        {                                             //element.length==0时,构造空链表
            rear.next=new Node<T>(element[i],null);   //尾插入,创建结点链入rear结点之后
            rear = rear.next;                         //rear指向新的链尾结点
        }
    }

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

    //以下length()、toString()、get()、set()方法基于单链表遍历算法
    public int length()                               //返回单链表长度,O(n)
    {
        int i=0; 
        Node<T> p=this.head.next;                     //p从单链表第一个结点开始
        while (p!=null)                               //若单链表未结束
        {   i++;
            p = p.next;                               //p到达后继结点
        }
        return i;
    }
    
    //返回单链表所有元素的描述字符串,形式为“(,)”,覆盖Object类的toString()方法,O(n)
    public String toString()
    {
        String str="(";
        for (Node<T> p = this.head.next;  p!=null;  p=p.next) 
        {   str += p.data.toString();
            if (p.next!=null) 
                str += ",";                                //不是最后一个结点时后加分隔符
        }
        return str+")";                                    //空表返回()
    }

    public T get(int i)                //返回第i(≥0)个元素,若i<0或大于表长则返回null,O(n)
    {
        if (i>=0)
        {
            Node<T> p=this.head.next;
            for (int j=0; p!=null && j<i; j++)
                p = p.next;
            if (p!=null)
                return p.data;                             //p指向第i个结点
        }
        return null;                                       //当i<0或大于表长时
    }
   
    //设置第i(≥0)个元素值为x。若i<0或大于表长则抛出序号越界异常;若x==null,不操作。O(n)
    public void set(int i, T x)
    {
        if (x==null)  return;                              //不能设置元素为空对象
        Node<T> p=this.head.next;
        for (int j=0; p!=null && j<i; j++)
            p = p.next;
        if (i>=0 && p!=null)
            p.data = x;                                    //p指向第i个结点
        else throw new IndexOutOfBoundsException(i+"");    //抛出序号越界异常
    }
    
    //以下insertAfter()、insert()、append()算法讨论单链表插入操作    
/*    //插入x作为p结点的后继结点,若操作成功返回新插入结点;否则返回null,O(1)
    public Node<T> insertAfter(Node<T> p, T x)    
    {
        if (x==null || p==null)
            return null; 
        Node<T> q=new Node<T>(x, p.next);             //插入x作为p结点的后继结点
        p.next = q; 
        return q;
    }*/
    
    //插入第i(≥0)个元素值为x。若x==null,不插入。
    //若i<0,插入x作为第0个元素;若i大于表长,插入x作为最后一个元素。O(n)
    public void insert(int i, T x) 
    {
        if (x==null)  return;                         //不能插入空对象         
        Node<T> p=this.head;                          //p指向头结点
        for (int j=0;  p.next!=null && j<i;  j++)     //寻找插入位置
            p = p.next;                               //循环停止时,p指向第i-1结点或最后一个结点
        p.next = new Node<T>(x, p.next);              //插入x作为p结点的后继结点,包括头插入(i<=0)、中间/尾插入(i>0)
    }
    public void append(T x)                           //在单链表最后添加x对象,O(n)
    {
        insert(Integer.MAX_VALUE, x);                //遍历一次
//      insert(this.length(), x);                  //需遍历单链表两次,效率较低
//      this.insertAfter(this.getLast(),x)!=null;      //遍历一次
    }
    /*    
    //将x对象插入在序号为i结点,若操作成功返回新插入结点;否则返回null,O(n)
    public Node<T> insert(int i, T x)    
    {
        if (x==null)
            return null;                              //不能插入空对象
        Node<T> p=this.head;                          //p指向头结点
        for (int j=0; p.next!=null && j<i; j++)       //寻找插入位置
            p = p.next;                               //循环停止时,p指向第i-1结点或最后一个结点
        Node<T> q=new Node<T>(x, p.next);             //插入x作为p结点的后继结点
        p.next = q;                                   //包括头插入(i<=0)、中间/尾插入(i>0)
        return q;
    }*/
    
    
    //以下removeAfter()、remove()、removeAll()算法实现单链表删除操作
/*    //删除p结点的后继结点,若操作成功返回删除结点;否则返回null,O(1)
    public Node<T> removeAfter(Node<T> p)    
    {
        if (p==null || p.next==null)
            return null; 
        Node<T> q=p.next;
        p.next = q.next;                              //删除p结点的后继结点q
        return q;
    }*/
    
    //删除第i(≥0)个元素,返回被删除对象。若i<0或i大于表长,不删除,返回null。O(n)
    public T remove(int i)
    {
        if (i>=0)
        {
            Node<T> p=this.head;
            for (int j=0;  p.next!=null && j<i;  j++)      //定位到待删除结点(i)的前驱结点(i-1)
                p = p.next;
            if (p.next!=null)
            {
                T old = p.next.data;                       //获得原对象
                p.next = p.next.next;                      //删除p的后继结点
                return old;
            }
        }
        return null;                                       //当i<0或大于表长时
//        throw new IndexOutOfBoundsException(i+"");         //抛出序号越界异常
    }

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

    /* 7.  提高单链表操作效率的措施
                    算法可行,但效率低,时间复杂度是O(n*n)。
        public String toString()
        {
            String str="(";
            if (this.length()!=0)
            {
                for(int i=0; i<this.length()-1; i++)
                    str += this.get(i).toString()+", ";
                str += this.get(this.length()-1).toString();
            }
            return str+")";
        }
    */
    
    //8.  单链表的浅拷贝与深拷贝
    //深拷贝构造方法,复制单链表list的所有结点构造新的单链表
    public SinglyLinkedList(SinglyLinkedList<T> list)
    {
        this();                                       //创建空单链表,只有头结点
        Node<T> rear = this.head;
        for (Node<T> p=list.head.next;  p!=null;  p=p.next)  //若l
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值