单链表——基本操作

1.获取链表第i个数据的算法思路

  1. 声明一个结点p指向链表第一个结点,初始化j从1开始
  2. 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
  3. 若到链表末尾p为空,则说明第i个元素不存在
  4. 否则查找成功,返回结点p的数据

2.单链表第i个数据插入结点的算法思路

  1. 声明一结点p指向链表第一个结点,初始化j从1开始
  2. 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
  3. 若到链表末尾p为空,则说明第i个元素不存在
  4. 否则查找成功,在系统中生成一个空结点s
  5. 将数据元素e赋值给s->data
  6. 单链表的插入标准语句s->next=p->next;p->next=s
  7. 返回成功

3.单链表第i个数据删除结点的算法思路

  1. 声明一结点p指向链表第一个结点,初始化j从1开始
  2. 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一结点,j累加1
  3. 若到链表末尾p为空,则说明第i个元素不存在
  4. 否则查找成功,将欲删除的结点p->next赋值给q
  5. 单链表的删除标准语句p->next=q->next
  6. 将q结点中的数据赋值给e,作为返回
  7. 释放q结点
  8. 返回成功

分析一下刚才我们讲解的单链表插入和删除算法,我们发现,它们其实都是由两部分组成:第一部分就是遍历查找第i个结点;第二部分就是插入和删除结点。

4.单链表整表创建的算法思路

  1. 声明一结点p和计数器变量i
  2. 初始化一空链表L
  3. 让L的头结点的指针指向NULL,即建立一个带头结点的单链表
  4. 循环:
  • 生成一新结点赋值给p
  • 随机生成一数字赋值给p的数据域p->data
  • 将p插入到头结点与前一新节点之间

     头插法,尾插法

5.单链表的整表删除

  1. 声明一结点p和q
  2. 将第一个结点赋值给p
  3. 循环:
  • 将下一结点赋值给q
  • 释放p
  • 将q赋值给p

 

Java代码实现,以下代码实现了单链表的各种操作  

/**
 * 结点类的描述
 * 
 * 单链表是由若干个结点连接而成,要实现单链表,首先需要设计结点类
 * 
 * 结点类由data和next组成
 * 
 * data是数据域,用来存放数据元素的值
 * next是指针域,用来存放后继结点的地址
 * 
 * @author acer
 *
 */
public class Node
{
    private Object data; //存放结点值
    
    private Node next; //后继结点的引用
    
    //无参数时的构造方法
    public Node()
    {
        this(null, null);
    }
    
    //带一个参数的构造方法
    public Node(Object data)
    {
        this(data, null);
    }
    
    //带两个参数的构造方法
    public Node(Object data, Node next)
    {
        this.data = data;
        this.next = next;
    }

    public Object getData()
    {
        return data;
    }

    public void setData(Object data)
    {
        this.data = data;
    }

    public Node getNext()
    {
        return next;
    }

    public void setNext(Node next)
    {
        this.next = next;
    }
}

创建一个接口

public interface IList
{
    public void clear();
    public boolean isEmpty();
    public int length();
    public Object get(int i) throws Exception;
    public void insert(int i, Object x) throws Exception;
    public void remove(int i) throws Exception;
    public int indexOf(Object x);
    public void display();
}
/**
 * 单链表类的描述
 * 
 * 由于单链表只需一个头指针就能唯一的标示它,所以单链表类的成员变量只需设置一个头指针即可
 * 
 * @author acer
 * 
 */
public class LinkList implements IList
{
    //单链表的头指针
    private Node head;

    public LinkList()
    {
        //初始化头结点
        head = new Node();
    }

    public LinkList(int n, boolean Order) throws Exception
    {
        this();
        if (Order)
        {
            create1(n);
        } else
        {
            create2(n);
        }
    }

    // 用尾插法顺序建立单链表,其中n为单链表的结点个数
    public void create1(int n) throws Exception
    {
        //构造用于输入对象
        Scanner sc = new Scanner(System.in);
        
        for(int j = 0; j < n; j++)
        {
            //生成新结点,插入到表尾
            insert(length(), sc.next());
        }
    }

    // 用头插法逆位序建立单链表,其中n为单链表的结点个数
    public void create2(int n) throws Exception
    {
        /*
         * 构造用于输入对象
         * 
         * Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配
         * 然后可以使用不同的 next 方法将得到的标记转换为不同类型的值。
         */
        Scanner sc = new Scanner(System.in);

        for (int j = 0; j < n; j++)
        {
            //生成新结点,插入到表头
            insert(0, sc.next());
        }
    }

    // 将一个已经存在的带头结点单链表置为空表
    @Override
    public void clear()
    {
        head.setData(null);
        
        head.setNext(null);
    }

    // 判断带头结点的单链表是否为空
    @Override
    public boolean isEmpty()
    {
        return head.getNext() == null;
    }

    // 求带头结点的单链表的长度
    @Override
    public int length()
    {
        Node p = head.getNext();
        
        int lenth = 0;
        
        while(p != null)
        {
            p = p.getNext();
            
            ++lenth;
        }
        
        return lenth;
    }

    /*
     * 读取带头结点的单链表中的第i个结点
     * 
     * 时间复杂度为O(n)
     */
    @Override
    public Object get(int i) throws Exception
    {
        // 初始化,p指向首结点,j为计数器
        Node p = head.getNext();

        int j = 0;

        // 从首结点开始向后查找,直到p指向第i个结点或p为空
        while (p != null && j < i)
        {
            // 指向后继结点
            p = p.getNext();

            // 极速器加1
            ++j;
        }

        // i小于0或者大于表长减1
        if (j > i || p == null)
        {
            // 抛出异常
            throw new Exception("第" + i + "个元素不存在");
        }

        // 返回结点p的数据域的值
        return p.getData();
    }

    /*
     * 在带头结点的单链表中的第i个结点之前插入一个值为x的新结点
     * 
     * 时间复杂度为O(n)
     */
    @Override
    public void insert(int i, Object x) throws Exception
    {
        // 初始化,p指向首结点,j为计数器
        Node p = head;

        int j = -1;

        // 寻找第i个结点的前驱
        while (p != null && j < i - 1)
        {
            p = p.getNext();

            // 计数器加1
            ++j;
        }

        // i不合法
        if (j > i - 1 || p == null)
        {
            // 抛出异常
            throw new Exception("插入位置不合法");
        }

        // 生成新结点
        Node s = new Node(x);

        // 修改链,使新结点插入到单链表中
        s.setNext(p.getNext());

        p.setNext(s);
    }

    /*
     * 在不带头结点的单链表的第i个结点之前插入一个数据域值为x的新结点
     * 
     * 时间复杂度为O(n)
     */
    public void insert2(int i, Object x) throws Exception
    {
        // 初始化,p指向首结点,j为计数器
        Node p = head;

        int j = 0;

        // 用i = -1\0\1测试
        while (p != null && j < i - 1)
        {
            p = p.getNext();

            ++j;
        }

        if (j > i || p == null)
        {
            throw new Exception("插入位置不合法");
        }

        Node s = new Node(x);

        // 插入位置为表头时
        if (i == 0)
        {
            s.setNext(head);

            head = s;
        }
        // 插入位置为表的中间或表尾时
        else
        {
            s.setNext(p.getNext());

            p.setNext(s);
        }
    }

    /*
     * 删除单链表中的第i个结点
     * 
     * 时间复杂度为O(n)
     */
    @Override
    public void remove(int i) throws Exception
    {
        // 初始化,p指向首结点,j为计数器
        Node p = head;

        int j = -1;

        // 寻找第i个结点的前驱
        while (p.getNext() != null && j < i - 1)
        {
            p = p.getNext();

            ++j;
        }
        if (j > i - 1 || p.getNext() == null)
        {
            throw new Exception("删除位置不合法");
        }

        // 修改链指针,使待删除结点从单链表中脱离
        p.setNext(p.getNext().getNext());

    }

    /*
     * 在单链表中查找值为x的结点
     * 
     * 时间复杂度为O(n)
     */
    @Override
    public int indexOf(Object x)
    {
        // 初始化,p指向首结点,j为计数器
        Node p = head.getNext();

        int j = 0;

        // 下面从单链表中的首结点开始查找,直到p.getData()为x或到达单链表的表尾
        while (p != null && !p.getData().equals(x))
        {
            // 指向下一个结点
            p = p.getNext();

            // 计数器加1
            ++j;
        }

        // 若p指向单链表中的某个结点,返回值为x的结点在单链表中的位置
        if (p != null)
        {
            return j;
        } else
        {
            // 值为x的结点不在链表中
            return -1;
        }
    }

    // 输出单链表中的所有结点
    @Override
    public void display()
    {
        //取出带头结点的单链表中的首结点
        Node p = head.getNext();
        
        while(p != null)
        {
            //输出结点的值
            System.out.print(p.getData() + " ");
            
            //取下一个结点
            p = p.getNext();
        }
        
        //换行
        System.out.println();
    }
}

 

posted @ 2018-04-13 00:59  Rainyn  阅读(11001)  评论(0编辑  收藏  举报