zoukankan      html  css  js  c++  java
  • 链表

    链表是一种数据结构,类似于长长的锁链串联起来一组对象。链表分为单链表和双链表,对于单链表来说,数据的查找只能从第一个数据开始,每一个数据只能顺着找到下一个数据,无法返回,对于双向链表,每个数据可以同时找到它的上一个节点和下一个节点。

    单向链表如下所示

    可以看出,链表包括两部分信息,一个是多个的节点,另一个是头节点和各个节点之间的连接关系。

    对于节点,我们可以定义一个节点类来描述,这个节点类药包括链表指针和值,对于第二部分信息,首先记录头节点,然后将每一个链表指针指向下一个即可。

    此外,为了方便使用,链表类中我们还需要提供链表长度、节点位置、链表的增删改查等功能。

    链表的基本结构和需要实现的函数功能如下:

    package dataStructure;
    
    public class CopyOfListNode {
    	class Node {
    		public Node next = null;
    		public int val;
    		public Node(int val){
    			this.val = val;
    		}
    	}
    	
    	private int listSize;
    	private Node head = null;
    	/**
    	 * 判定节点是否为空
    	 * @return
    	 */
    	public boolean isEmpty(){
    		return listSize == 0;}
    	
    	/**
    	 * 返回链表大小
    	 * @return
    	 */
    	public int size(){
    		return listSize;
    	}
    	
    	/**
    	 * 获取指定位置的节点
    	 * @param index
    	 * @return
    	 */
    	public int get(int index){
    		return -1;
    	}
    	
    	/**
    	 * 获取节点在链表中的位置
    	 * @param node
    	 * @return
    	 */
    	public int indexOf(int value){
    		return -1;
    	}
    	
    	/**
    	 * 添加节点
    	 * @param index
    	 * @param node
    	 */
    	public void add(int value){
    		
    	}
    	
    	/**
    	 * 删除节点
    	 * @param index
    	 */
    	public void delete(int index){
    		
    	}
    	
    	/**
    	 * 插入节点
    	 * @param index
    	 * @param node
    	 */
    	public void insert(int index, int value){
    		
    	}
    	
    	/**
    	 * 打印链表所有节点
    	 */
    	public void printList(){
    		
    	}
    	
    	/**
    	 * 构造测试用例
    	 * @param args
    	 */
    	public static void main(String[] args){
    		
    	}
    }
    

      需要实现的功能有:判定链表是否为空、链表的大小、获取指定位置的节点信息、获取节点的位置、添加节点、删除节点、插入节点、打印链表几个功能

    需要维持的成员变量有链表大小listSize,和头节点head,功能的实现如下:

    1.判断链表是否为空和链表大小的功能,我们可以直接根据链表大小返回。

    代码如下:

    /**
    	 * 判定节点是否为空
    	 * @return
    	 */
    	public boolean isEmpty(){
    		return listSize == 0;}
    	
    	/**
    	 * 返回链表大小
    	 * @return
    	 */
    	public int size(){
    		return listSize;
    	}
    

      2.获取指定位置的节点

    根据链表的性质,从头节点开始依次移动直到到达指定位置,需要注意的是需要先判定索引是否有效,防止出现空指针异常

    /**
    	 * 获取指定位置的节点
    	 * @param index
    	 * @return
    	 */
    	public int get(int index){
    		Node node  = head;
    		if(index < 0 || index >= listSize)
    			return -1;
    		for(int i=0; i<index; i++){
    			//移到下一节点
    			node = node.next;
    		}
    		return node.val;
    	}
    

      3.获取节点在链表中的位置

    遍历链表,知道找到所需节点,或者遍历完成推出节点返回未找到信息

    	/**
    	 * 获取节点在链表中的位置
    	 * @param node
    	 * @return
    	 */
    	public int indexOf(int value){
    		int index = 0;
    		Node currentNode = head;
    		while(currentNode!=null && currentNode.val!=value){
    			//转移到下一个节点
    			currentNode = currentNode.next;
    			index++;
    		}
    		//确认是否找到所需元素
    		if(currentNode == null)
    			return -1;
    		else
    			return index;
    	}
    

      4.添加节点

    添加节点需要分两种情况考虑,头节点和其他节点,因为头节点没有前节点,只需要直接将head赋值即可,对于后续节点,需要将链表内最后一个节点的指针指向所要添加的节点,另外,需要注意将链表大小变量listSize+1,方便统计大小

    代码如下:

    /**
    	 * 添加节点
    	 * @param index
    	 * @param node
    	 */
    	public void add(int value){
    		if(head == null){
    			head = new Node(value);
    		}else{
    			Node nd = head;
    			while(nd.next != null){
    				nd = nd.next;
    			}
    			nd.next = new Node(value);
    		}
    		listSize++;
    	}
    

      5.删除节点

    删除节点主要是删除节点的连接关系,分为删除头节点,删除尾节点,删除中间节点。

     删除头节点,删除头节点的连接关系,将第二个作为新的头节点即可

    删除尾节点,将尾节点与前一个节点的连接关系去掉即可

    删除中间节点,将要删除节点前后连接关系删除,并将前一个节点直接指向后一个节点即可

     需要注意的是,对于删除头节点和中间节点,需要提前将后半段链表的信息保存下来,防止丢失,删除后的节点在java中会自动被GC回收

    代码如下:

     1 /**
     2      * 删除节点
     3      * @param index
     4      */
     5     public void delete(int index){
     6         //首先检查节点是否存在
     7         if(index >= listSize || index < 0){
     8             System.out.println("该节点不存在");
     9             return;
    10         }
    11         //定位到要删除节点
    12         if(index == 0){
    13             //首节点
    14             head = head.next;
    15         }else{
    16             //定位到前一个节点
    17             Node currentNode = head;
    18             for(int i=0; i<index-1; i++){
    19                 currentNode = currentNode.next;
    20             }
    21             if(index == listSize)
    22                 //尾节点处理
    23                 currentNode.next = null;
    24             else
    25                 //中间节点
    26                 currentNode.next = currentNode.next.next;
    27         }
    28         listSize--;
    29     }

    6.打印链表

    根据链表信息依次打印即可

    代码:

     1 /**
     2      * 打印链表所有节点
     3      */
     4     public void printList(){
     5         Node currentNode = head;
     6         while(currentNode!=null){
     7             System.out.print(currentNode.val+" ");
     8             currentNode = currentNode.next;
     9         }
    10     }

    整体的代码及测试用例如下:

      1 package dataStructure;
      2 
      3 public class ListNode {
      4     class Node {
      5         public Node next = null;
      6         public int val;
      7         public Node(int val){
      8             this.val = val;
      9         }
     10     }
     11     
     12     private int listSize;
     13     private Node head = null;
     14     /**
     15      * 判定节点是否为空
     16      * @return
     17      */
     18     public boolean isEmpty(){
     19         return listSize == 0;}
     20     
     21     /**
     22      * 返回链表大小
     23      * @return
     24      */
     25     public int size(){
     26         return listSize;
     27     }
     28     
     29     /**
     30      * 获取指定位置的节点
     31      * @param index
     32      * @return
     33      */
     34     public int get(int index){
     35         Node node  = head;
     36         if(index < 0 || index >= listSize)
     37             return -1;
     38         for(int i=0; i<index; i++){
     39             //移到下一节点
     40             node = node.next;
     41         }
     42         return node.val;
     43     }
     44     
     45     /**
     46      * 获取节点在链表中的位置
     47      * @param node
     48      * @return
     49      */
     50     public int indexOf(int value){
     51         int index = 0;
     52         Node currentNode = head;
     53         while(currentNode!=null && currentNode.val!=value){
     54             //转移到下一个节点
     55             currentNode = currentNode.next;
     56             index++;
     57         }
     58         //确认是否找到所需元素
     59         if(currentNode == null)
     60             return -1;
     61         else
     62             return index;
     63     }
     64     
     65     /**
     66      * 添加节点
     67      * @param index
     68      * @param node
     69      */
     70     public void add(int value){
     71         if(head == null){
     72             head = new Node(value);
     73         }else{
     74             Node nd = head;
     75             while(nd.next != null){
     76                 nd = nd.next;
     77             }
     78             nd.next = new Node(value);
     79         }
     80         listSize++;
     81     }
     82     
     83     /**
     84      * 删除节点
     85      * @param index
     86      */
     87     public void delete(int index){
     88         //首先检查节点是否存在
     89         if(index >= listSize || index < 0){
     90             System.out.println("该节点不存在");
     91             return;
     92         }
     93         //定位到要删除节点
     94         if(index == 0){
     95             //首节点
     96             head = head.next;
     97         }else{
     98             //定位到前一个节点
     99             Node currentNode = head;
    100             for(int i=0; i<index-1; i++){
    101                 currentNode = currentNode.next;
    102             }
    103             if(index == listSize)
    104                 //尾节点处理
    105                 currentNode.next = null;
    106             else
    107                 //中间节点
    108                 currentNode.next = currentNode.next.next;
    109         }
    110         listSize--;
    111     }
    112     
    113     /**
    114      * 插入节点
    115      * @param index
    116      * @param node
    117      */
    118     public void insert(int index, int value){
    119         //首先检查插入位置是否合适
    120         if(index >= listSize || index < 0){
    121             System.out.println("索引无效");
    122             return;
    123         }
    124         //分位置插入
    125         if(index == 0){
    126             //头节点,只保存后面节点
    127             Node tmpNode = head;//保存后面当前位置节点信息
    128             head = new Node(value);
    129             head.next = tmpNode;
    130         }else{
    131             //中间节点,保存前一个节点和后节点信息
    132             Node preNode = head;
    133             for(int i=0; i<index-1; i++){
    134                 preNode = preNode.next;
    135             }
    136             Node currentNode = preNode.next;
    137             preNode.next = new Node(value);
    138             preNode.next.next = currentNode;
    139         }
    140         listSize++;
    141     }
    142     
    143     /**
    144      * 打印链表所有节点
    145      */
    146     public void printList(){
    147         Node currentNode = head;
    148         while(currentNode!=null){
    149             System.out.print(currentNode.val+" ");
    150             currentNode = currentNode.next;
    151         }
    152     }
    153     
    154     public static void main(String[] args){
    155         ListNode testList = new ListNode();
    156         for(int i=0; i<50; i++)
    157             testList.add(i);
    158         System.out.println("链表是否为空:"+testList.isEmpty());
    159         System.out.println("链表大小:"+testList.size());
    160         System.out.println("获取头节点:"+testList.get(0));
    161         System.out.println("获取尾节点:"+testList.get(49));
    162         System.out.println("获取位置为10的中间节点:"+testList.get(10));
    163         System.out.println("获取节点值10的位置:"+testList.indexOf(10));
    164         System.out.println("获取值为1000的节点位置:"+testList.indexOf(1000));
    165         testList.delete(0);
    166         System.out.println("删除头节点后大小:"+testList.size());
    167         testList.delete(testList.size()-1);
    168         System.out.println("删除尾节点后大学:"+testList.size());
    169         testList.delete(2);
    170         System.out.println("删除中间点2后大小:"+testList.size());
    171         System.out.println("打印链表:");
    172         testList.printList();
    173         testList.insert(0, 0);
    174         System.out.println("添加0到头节点后大小:"+testList.size());
    175         testList.insert(3, 3);
    176         System.out.println("添加3到中间节点3处大小:"+testList.size());
    177         System.out.println("打印链表:");
    178         testList.printList();
    179     }
    180 }

     此外还有循环链表、双向链表,实现方式基本如此

  • 相关阅读:
    深入剖析.NET运行机制
    在浏览器地址中加参数
    mysql 中文乱码
    今天在看一些面试题的时候遇到的一个关于strcmp()返回值的细节问题
    如何在学习过程中统一IDE的编码!
    通过文件方式,在文件内容开头写入字符串!
    Java编写圆的相关计算
    leetcode 上的Counting Bits 总结
    cocos2dx打包apk
    CEGUI0.8.4例子
  • 原文地址:https://www.cnblogs.com/feichangnice/p/7663533.html
Copyright © 2011-2022 走看看