• 数据结构-----链表的实现


    单链表

        1,链表存储特点

          ① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
          ② 链表中结点的逻辑次序和物理次序不一定相同。

        2,线性表的单链表存储结构如:

        3,链表建立方法(时间复杂度为O(n))

          头插入法:s->data=d;s->next=head;head=s(head头指针,s新建节点)

           尾插入法:s->data=d;r->next=s;r=s;(r尾节点)

          带头结点及作用:

             1,由于开始结点的位置被存放在头结点的指针域中,所以在链表的第一个位置上的操作就和在表的其它位置上操作一致,无须进行特殊处理;

            2,无论链表是否为空,其头指针都是指向头结点的非空指针(空表中头结点的指针域空),因此空表和非空表的处理也就统一了。

          单链表常用操作:

            1,查询 时间复杂度为O(n)

            2,插入:往节点p后插入:s->data=x;s->next=p->next;p->next=s;仅仅插入时间复杂度为O(1)

            3,删除:删除r之后的节点:p=r->next;r->next=p->next;free(p)仅仅删除时间复杂度为O(1)

    单链表的Java实现:

    package dataStructByJava;
    
    public class LinkList<T> {
    //使用Node内部类来表示单链表的节点,这样就不需要为Node类的字段添加get方法和set方法就能访问这些字段
        private class Node{
            private T data;
            private Node next;
            private Node(){           
            }
            private Node(T data, Node next){
                this.data = data;
                this.next = next;
            }
        }    
        private Node header;//保存链表的头结点
        private Node tail;//保存链表的尾结点,采用尾插法添加结点时,不需要遍历整个链表
        private int size;//保存链表中已包含的节点数    
        public LinkList(){
            header = tail = null;
        }
        public LinkList(T element){
            header = new Node(element, null);
            tail = header;
            size++;
        }    
        public int length(){
            return size;
        }    
        //获得索引为index处的元素值,注意:索引从0开始
        public T get(int index){
            return getNodeByIndex(index).data;
        }
        private Node getNodeByIndex(int index){
            if(index < 0 || index > size - 1)
                throw new IndexOutOfBoundsException("单链表越界");
            Node current = header;
            for(int i = 0; (i < size) && (current != null); i++, current = current.next)
                if(i == index)
                    return current;
            return null;
        }   
        //返回链表中指定元素的索引,若指定元素不存在,返回-1
        public int locate(T element){
            Node current = header;
            for(int i = 0; i < size && current != null; i++, current = current.next)
                if(current.data.equals(element))
                    return i;
            return -1;
        }
        //在某个位置上插入值
        public void insert(T element, int index){
            if(index < 0 || index > size)
                throw new IndexOutOfBoundsException("单链表索引越界");
            if(header == null)//链表是空链表时
                add(element);
            else{
                if(index == 0)//在表头插入
                    addAtHeader(element);
                else{
                    Node prev = getNodeByIndex(index - 1);//获取插入结点的前驱
                    prev.next = new Node(element, prev.next);
                    size++;
                }
            }
        }    
        //采用尾插法为链表增加新节点
        public void add(T element){
            if(header == null){
                header = new Node(element, null);
                tail = header;
            }
            else{
                Node newNode = new Node(element, null);
                tail.next = newNode;
                tail = newNode;
            }
            size++;
        }    
        //采用头插法为链表增加新节点
        public void addAtHeader(T element){
            header = new Node(element, header);//新建的结点的next 需要指向 header结点
            if(tail == header)//如果插入之前是空链表
                tail = header;
            size++;
        }    
        public T delete(int index){
            if(index < 0 || index > size - 1)
                throw new IndexOutOfBoundsException("链表索引越界");
            Node del;
            //待删除的是header节点
            if(index == 0){
                del = header;
                header = header.next;
            }
            else{
                Node prev = getNodeByIndex(index - 1);//获取待删节点的前驱
                del = prev.next;//del 指向待删除的节点
                prev.next = del.next;
            }
            del.next = null;//将待删节点从链表中脱离出去
            size--;
            return del.data;
        }    
        //根据指定的元素来删除节点
        public boolean deleteByElement(T element){
            //链表为空
            if(empty()){
                return false;
            }
            //待删元素为第一个元素
            else if(header.data.equals(element)){
                Node del = header;
                header = header.next;
                if(tail == header)//说明整个链表中只有一个元素,tail也应当置null
                    tail = null;
                del.next = null;
                size --;
                return true;
            }
            //待删元素为链表中其他元素
            else{
                Node del = header.next;
                Node prev = header;
                while(del != null){
                    if(del.data.equals(element)){
                        if(tail == del)//如果待删元素是最后一个元素,需要将tail指针指向其前驱
                            tail = prev;
                        prev.next = del.next;
                        del.next = null;
                        size--;
                        return true;
                    }
                    //若没有找到element,则继续下一轮的循环
                    prev = del;
                    del = del.next;
                }
                return false;
            }
        }   
        //删除链表中的最后一个元素
        public T remove(){
            return delete(size - 1);
        }
        
        //判断链表是否为空
        public boolean empty(){
            boolean result;
            if(size == 0){
                assert header == null;//当出现链表为空,但size不为0时,使用断言能够帮助找到逻辑错误
                result = true;
            }
            else{
                assert header != null;
                result = false;
            }
            return result;
            //return size == 0;
        }
        
        //清空链表
        public void clear(){
            header = tail = null;
            size = 0;
        }    
        public String toString(){
            if(empty())
                return "[]";
            else{
                StringBuilder sb = new StringBuilder("[");
                for(Node current = header; current != null; current = current.next)
                    sb.append(current.data.toString() + ", ");
                int len = sb.length();
                //注意删除最后添加的两个多余的字符
                return sb.delete(len - 2, len).append("]").toString();
            }
        }
        public static void main(String[] args){
            LinkList<String> list=new LinkList<String>();
            //用头插法创建表,创建顺序与输出顺序相反
            for(int i=0;i<5;i++)
                list.addAtHeader("No."+i);
            //输出:[No.4, No.3, No.2, No.1, No.0]
            System.out.println(list.toString());
            //查找某个元素,返回下标如No.2,输出2
            System.out.println(list.locate("No.2"));
            //添加在index 3插入No.25
            list.insert("No.25", 3);
            System.out.println(list.toString());
            //删除No.25
            list.deleteByElement("No.25");
            System.out.println(list);
            //清空链表
            list.clear();
            System.out.println(list);
            //尾插入发构建链表 结果是[No.0, No.1, No.2, No.3, No.4]
            for(int i=0;i<5;i++){
                list.add("No."+i);
            }
            System.out.println(list);
        }
    }
    View Code

        参考资料:

          1,数据结构概念

          2,数据结构Java单链表的简单实现

  • 相关阅读:
    nginx文件类型错误解析漏洞
    js 获取URL中的参数并转换为对象
    postman
    php curl参数详解
    php 两变量值互换 方法
    PHP 命名空间与spl_autoload_register() 自动加载机制
    php命名大小问题
    PHP实现冒泡排序
    使用 PHPStorm + Xdebug 实现断点调试(二)
    TSPL学习笔记(2):过程和变量绑定
  • 原文地址:https://www.cnblogs.com/ksWorld/p/6759426.html
Copyright © 2020-2023  润新知