zoukankan      html  css  js  c++  java
  • 链表

    线性表分为顺序表和链表;

    1、顺序存储结构和链式存储结构的区别

      顺序存储结构是在内存中开辟一个连续的空间用来存储数据,因此对于内存的需求和苛求,必须是连续的空间,在数据查找(特别是不按照规律排序的数据),时间复杂度较少,效率高。

      链式存储结构是采取链表指针来指示数据的存储位置,这就可以是在内存中随意的存储,没有必要连续存储空间的要求,对于内存的要求相对比较容易。但是,要是从小到大顺序排列的数据时,链式存储结构的时间复杂度较小,效率高。但是要是不规则排列的数据一般时间复杂度较高,效率较低。

    2、单向链表代码:

      

    package com.zxc.LinklistLearning;
    
    import org.junit.Test;
    
    /**
     * Created by Administrator on 2018/2/17 0017.
     * 单向链表
     */
    public class LinkList {
       public class Node{
           public String data;
           private Node next;
    
           public Node(String data,Node next){
               this.data=data;
               this.next=next;
           }
       }
    
       private Node header;
       private Node tail;
       private int size;
       public LinkList(){
           header=null;
           tail=null;
       }
    
    
       public void addTail(String data){//尾插法
           if(header==null){
                header=new Node(data,null);
                tail=header;
           }else {
               Node newNode=new Node(data,null);
               tail.next=newNode;
               tail=newNode;
           }
           size++;
       }
    
       public void addHeader(String data){//头插法
           this.header=new Node(data,header);//创建新节点,让新节点的next指向原来的header,并以新创建的节点作为新header
           //如果插入前是空链表
           if(tail==null){
               tail=header;
           }
           size++;
       }
    
        /**
         *
         * @param index:要即将插入节点的索引号
         * @return:返回索引指定的现在的节点
         */
       public Node getNodeByIndex(int index){
           Node currentNode=header;//代表从头找
           for(int i=0;i<size;i++){
               if(i==index){
                   return currentNode;
               }
               currentNode=currentNode.next;
           }
           return null;
       }
    
        /**
         *
         * @param data:要插入的数据
         * @param index:索引处插入
         */
       public void insert(String data,int index) {
           if (index < 0 || index > size) {
               System.out.println("线性表索引越界");
           } else {
               if (header == null) {
                   this.addTail(data);
               } else {
                   if (index == 0) {
                       addHeader(data);
                   } else {
                       Node preNode = getNodeByIndex(index-1);
                       preNode.next=new Node(data,preNode.next);//先实例化右面,再赋值左侧
                   }
               }
           }
       size++;
       }
    
       public String delete(int index){
           Node del=null;
           if (index < 0 || index > size) {
               System.out.println("线性表索引越界");
           }
           if(index==0){
               del=header;
               header=header.next;
           }else{//多于一个节点
                Node prev=this.getNodeByIndex(index-1);
                del=prev.next;
                prev.next=del.next;
           }
           del.next=null;
           return del.data;
       }
    
        @Override
        public String toString() {
          StringBuffer sb=new StringBuffer();
          for(Node current=header;current!=null;current=current.next ){
            sb.append(current.data);
          }
           return sb.toString();
        }
    
        @Test
        public void ok(){
            this.addHeader("A");
            this.addHeader("B");
            this.addTail("C");
    
            System.out.println(this);
        }
    }

     三、双向链表

      每个节点保留两个引用prev,next,让prev指当前节点的上一个节点,让next指向当前节点的下一个节点,此时链表既可以向前也可以向后访问每个节点,这种形式的链表被称为双向链表。

      由于是双向的,我们查找元素的时候既可以从header处查找,也可以从tail处查找,从哪里查找取决于离哪个节点更近,一般地,可以通过被搜索的index值来判断它更靠近header,还是更靠近tail,如果index<size/2,可以判断位置更靠近header,应从header处搜索,反之应从tail处搜索。

    package com.zxc.LinklistLearning;
    
    import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
    import org.junit.Test;
    
    /**
     * Created by Administrator on 2018/2/18 0018.
     * 双向链表
     * */
    public class DeLinkList {
        private class Node{
            private String data;
            private Node prev;
            private Node next;
    
            public Node(String data,Node prev,Node next){
                this.data=data;
                this.prev=prev;
                this.next=next;
            }
        }
    
        private Node header;
        private Node tail;
        private int size;
        public DeLinkList(){
            header=null;
            tail=null;
        }
    
        public void addHeader(String data){//头插法
            this.header=new Node(data,null,header);//创建新节点,让新节点的next指向原来的header,并以新创建的节点作为新header
            //如果插入前是空链表
            if(tail==null){
                tail=header;
            }
            size++;
        }
    
        public void addTail(String data){//尾插法
            if(header==null){
                header=new Node(data,null,null);
                tail=header;
            }else {
                Node newNode=new Node(data,tail,null);
                tail.next=newNode;
                tail=newNode;
            }
            size++;
        }
    
        /**
         *
         * @param index:要即将插入节点的索引号
         * @return:返回索引指定的现在的节点
         */
        public Node getNodeByIndex(int index){
            Node currentNode=header;//代表从头找
            for(int i=0;i<size;i++){
                if(i==index){
                    return currentNode;
                }
                currentNode=currentNode.next;
            }
            return null;
        }
    
        /**
         *
         * @param data:要插入的数据
         * @param index:索引处插入
         */
        public void insert(String data,int index) {
            if (index < 0 || index > size) {
                System.out.println("线性表索引越界");
            } else {
                if (header == null) {
                    this.addHeader(data);
                } else {
                    if (index == 0) {
                        addHeader(data);
                    } else {
                        Node preNode = getNodeByIndex(index-1);
                        Node current=new Node(data,preNode,preNode.next);
                        current.next.prev=current;
                        preNode.next=current;
    
                    }
                }
            }
            size++;
        }
    
        public String delete(int index){
            Node del=null;
            if (index < 0 || index > size) {
                System.out.println("线性表索引越界");
            }
            if(index==0){
                del=header;
                header=header.next;
            }else{//多于一个节点
                Node prev=this.getNodeByIndex(index-1);
                del=prev.next;
                prev.next=del.next;
                del.next.prev=prev;
            }
            del.next=null;
            return del.data;
        }
    
        @Override
        public String toString() {
            StringBuffer sb=new StringBuffer();
            for(Node current=header;current!=null;current=current.next){
                sb.append(current.data);
            }
            return sb.toString();
        }
    
        @Test
        public void ok(){
            addHeader("A");
            addTail("B");
            addHeader("C");
            insert("D",1);
            this.delete(2);
            System.out.println(this);
        }
    }

     四、链表高级使用技巧:打印两个有序链表的公共部分

      题目:给定两个有序链表的头指针head1,head2,打印两个链表的公共部分

      分析过程:1、如果head1的值小于head2,则head1往下移动。

           2、如果head2的值小于head1,则head2往下移动。

           3、如果head1的值与head2相等,则打印这个值,然后head1和head2都往下移动。

           4、head1或和head2有任何一个移动到null,这个过程停止。

    public class PrintCommonPart {
    
        public static class Node {
            public int value;
            public Node next;
            public Node(int data) {
                this.value = data;
            }
        }
    
        public static void printCommonPart(Node head1, Node head2) {
            System.out.print("Common Part: ");
            while (head1 != null && head2 != null) {
                if (head1.value < head2.value) {
                    head1 = head1.next;
                } else if (head1.value > head2.value) {
                    head2 = head2.next;
                } else {
                    System.out.print(head1.value + " ");
                    head1 = head1.next;
                    head2 = head2.next;
                }
            }
            System.out.println();
        }
    
        public static void printLinkedList(Node node) {
            System.out.print("Linked List: ");
            while (node != null) {
                System.out.print(node.value + " ");
                node = node.next;
            }
            System.out.println();
        }
    
        public static void main(String[] args) {
            Node node1 = new Node(2);
            node1.next = new Node(3);
            node1.next.next = new Node(5);
            node1.next.next.next = new Node(6);
    
            Node node2 = new Node(1);
            node2.next = new Node(2);
            node2.next.next = new Node(5);
            node2.next.next.next = new Node(7);
            node2.next.next.next.next = new Node(8);
    
            printLinkedList(node1);
            printLinkedList(node2);
            printCommonPart(node1, node2);
    
        }
    
    }

    五、约瑟夫环

      

    package com.zxc.LinklistLearning;
    public class Jhonsef {
        //定义结点,
        class Node{
            int data;
            Node next;
            Node(int data){
                this.data = data;
            }
        }
        public static void main(String[] args){
            new Jhonsef().yuekill();
        }
        public void yuekill(){
            int n = 3;//定义总人数n
            int m = 3;//和出圈数字m
            //初始化循环列表,头结点first和尾结点last
            Node first = new Node(0);
            first.next = first;  //一个节点的时候,头就是尾,尾就是头
            Node last = first;
    
    
            for(int i=1; i<n; i++){//形成单链表   0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
                Node temp = new Node(i);
                last.next = temp;
                last = last.next;
            }
    
            last.next = first;//0和16连接,最终让其首尾相连,形成循环链表 ,尾接头形成循环链表(last为尾结点)
            //以上就是约瑟夫环
    
            //执行出圈操作
            System.out.println("出圈顺序为:");
            while(last != last.next){
                //下面for循环后,last是第m个结点的前一个结点
                for(int i=1; i<m; i++){  //遍历要删除节点 前一个出圈数字
                    last = last.next;
                }
                //出循环之后,就是要删除的节点,删除第m个结点
                System.out.print(last.next.data+" "); //出圈的数字
                last.next = last.next.next;  //指向要删除的节点的下一节点
            }
            System.out.print("
    幸运者是:"+last.data);//原来是10号
        }
    
    }

    六、链表和数组的区别

      数组:定义时长度固定(在内存中也是连续的),有下标,不能任意删除某个元素

      链表:长度不固定(可以根据需要申请内存),没有下标,可以根据需要删除。C语言中的链表是通过指针把相邻的节点联系起来,也就是前一个节点通过指针来保存下一个节点的地址,所以如果能得到头结点就能得到下一个节点,一直到最后一个节点。而Java中的链表,由于没有指针,所以它不能使用指针来保存下一个节点的地址,但是我们可以保存下一个节点对象,这种方法叫做引用。

  • 相关阅读:
    volatile关键字
    线程的状态
    java中的匿名内部类
    java高精度实数和小数
    JS、JSP、ASP、CGI
    论文结构要求
    java中的标识符、关键字、保留字
    java IODemo
    Bagging和Boosting的区别
    由Memcached升级到 Couchbase的 Java 客户端的过程记录(一)
  • 原文地址:https://www.cnblogs.com/television/p/8452186.html
Copyright © 2011-2022 走看看