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 }

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

  • 相关阅读:
    HDU 6182 A Math Problem 水题
    HDU 6186 CS Course 位运算 思维
    HDU 6188 Duizi and Shunzi 贪心 思维
    HDU 2824 The Euler function 欧拉函数
    HDU 3037 Saving Beans 多重集合的结合 lucas定理
    HDU 3923 Invoker Polya定理
    FZU 2282 Wand 组合数学 错排公式
    HDU 1452 Happy 2004 数论
    HDU 5778 abs 数论
    欧拉回路【判断连通+度数为偶】
  • 原文地址:https://www.cnblogs.com/feichangnice/p/7663533.html
Copyright © 2011-2022 走看看