• 链表


    数组是编程语言中最常见也是很有用的数据结构,允许随机存取,相比于链表,数组能节约空间。但是他有两个缺陷:

      (1).数组的长度是固定的,改变数组的大小意味着需要创建一个新的数组,并从原数组中拷贝数据到新数组中;

      (2).数组数据在内存中一次连续存储,在实现插入删除操作会移动其他数据,使得开销变大。

      采用链式结构可以很好的克服这一局限,链式结构是存储数据和其他节点的链指针的节点集合。

    1.单向链表

      一个节点只包含节点数据和指向后继节点的指针,这样的链表成为单向链表。

      一个节点的java定义:

    public class IntNode{
      public int info;
      public IntNode next;
      public IntNode(int i){
        this(i,null);
      }
      public IntNode(int i,IntNode n){
        info = i;
        next = n;
      }
    }

    一个节点只包含两个域:info域 和 next域,前者用来存储信息,后者用来把节点连接在一起形成链表。

    有了节点的定义,要创建一个新的节点只需要给他 new 一下就好:

    IntNode p = new IntNode(10); //创建了一个数据域为10的节点
    p.next = new IntNode(9); //创建p的后继节点,数据域为9
    p.next.next = new IntNode(8); //创建第三个节点;

    现在出现一个问题,如果我想创建10000个节点,那岂不是得写9999个next,这也太复杂了吧

    一个简单的解决方案:在链表中同时保存两个指针: 一个指向链表的第一个节点;另一个指向链表的最后一个节点。

    单向链表封装如下:

    //*****************************IntSLList.java******************************
    //      singly linked list class to store integers
    
    public class IntSLList {
        private IntNode head, tail;
        public IntSLList() {
            head = tail = null;
        }
        public boolean isEmpty() {
            return head == null;
        }
        //在链表头添加节点
        public void addToHead(int e1) {
            head = new IntNode(e1,head);
            if(tail == null) {
                tail = head;
            }
        }
        //在链表尾添加节点
        public void addToTail(int e1) {
            if(!isEmpty()) {
                tail.next = new IntNode(e1);
                tail = tail.next;
            }
            else {
                head = tail = new IntNode(e1);
            }
        }
        //删除链表头节点并返回数据
        public int deleteFromHead() {
            int e1 = head.info;
            if(head == tail) {
                head = tail = null;
            }else {
                head = head.next;
            }
            return e1;
            
        }
        //从链表尾删除节点并返回数据
        public int deleteFromTail() {
            int e1 = tail.info;
            if(head == tail) {
                head = tail = null;
            }else {
                IntNode temp;
                for(temp = head;temp.next != tail;temp = temp.next) {
                    tail = temp;
                    tail.next = null;
                }
            }
            return e1;
        }
        
        //打印链表节点
        public void printAll() {
            for(IntNode t = head; t!=null;t = t.next) {
                System.out.println(t.info + " ");
            }
        }
        //查找节点
        public boolean isInList(int e1) {
            IntNode t;
            for(t = head; t != null && t.info != e1; t = t.next) {
                
            }
            return t != null;
        }
        //删除节点,该节点在链表任何位置
        public void delete(int e1) {
            if(!isEmpty()) {
                if(head == tail && e1 == head.info) {
                    head = tail = null;
                }else if(e1 == head.info){
                    head = head.next;
                }else {
                    IntNode pred,tmp;
                    for(pred = head, tmp = head.next; tmp != null && tmp.info != e1; pred = pred.next,tmp = tmp.next) {
                        
                    }
                    if(tmp != null) {
                        pred.next = tmp.next;
                        if(tmp == tail) {
                            tail = pred;
                        }
                    }
                }
            }
        }
        
    }

    上面的封装给出了整型链表的一般操作,包括插入,删除,查找,判断非空等,示例存储的数据类型是整型的,推广的一般的链表可以直接把info域声明为Object。

    单项链表的一个主要缺陷:由于节点只包含指向后继节点的指针,不能访问一个节点的前驱,使得在删除队尾数据时不得不遍历整个链表,对于一个包含很多数据的长链表来说,无疑会降低链表的操作速度。

     2.双向链表

      双向链表每个节点包含两个指针域,一个指向前驱节点,另一个指向后继节点。双向链表对于删除链表尾节点是十分方便的

    下面给出简单的整型双向链表的封装:

    //+++++++++++++++++++++++++++IntDLLNode.java++++++++++++++++++++++++++++++
    
     public class IntDLLNode{
        public int info;
        public IntDLLNode next, prev;
        public IntDLLNode(int e1) {
            this(e1,null,null);
        }
        public IntDLLNode(int e1,IntDLLNode n,IntDLLNode p) {
            info = e1;
            next = n;
            prev = p;
        }
    }
     
    //+++++++++++++++++++++++++++IntDLList.java++++++++++++++++++++++++++++++
    public class IntDLList {
        private IntDLLNode head, tail;
        
        public IntDLList() {
            head = tail = null;
        }
        //判断非空与否?
        public boolean isEmpty() {
            return head != null;
        }
        //在表尾添加节点
        public void addToTail(int e1) {
            if(!isEmpty()) {
                tail = new IntDLLNode(e1,null,tail);
                tail.prev.next = tail;
            }else {
                head = tail = new IntDLLNode(e1);
            }
        }
        //删除表尾的节点并返回该节点值
        public int removeFromTail() {
            int e1 = tail.info;
            if(head == tail) {
                head = tail = null; //表中只有一个节点
            }else {
                tail = tail.prev;
                tail.next = null;
            }
            return e1;
        }
    }

    3.循环链表

    将节点连接成环形成循环链表:表的节点必须是有限的,而且每个节点都必须有一个后继。

      3.1循环单向链表

      3.2循环双向链表

  • 相关阅读:
    web服务器iis安全设置
    Log explorer for sql server
    C#将image中的显示的图片转换成二进制
    .Net平台开发的技术规范与实践精华总结
    .net面试题整理
    Javascript 刷新框架及页面的方法总集
    WEB程序代码优化入手的几方面
    用js控制网页播放器
    SQL Server2000中死锁经验总结
    专家谈CSS设计
  • 原文地址:https://www.cnblogs.com/lc1475373861/p/10687974.html
Copyright © 2020-2023  润新知