链表

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

单向链表如下所示

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

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

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

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

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 }

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

原文地址:https://www.cnblogs.com/feichangnice/p/7663533.html