链表是区分于数组的一种地址不连续,没有顺序的数据接口,链表中的节点包含数据元素值和指针,指针指向链表的下一个节点。
使用链表无需像数组一样,需预先定义数据大小,也无需同集合需要扩容。但链表的缺点也很明显,链表读取数据需从头依次获取。不支持随机读取。
定义单向链表节点
定义单向链表类,其中有链表使用方法
- 如何获取链表中间节点
- 如何判断链表有环以及环的长度
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
public class LinkedNode
{
private static Logger logger = Logger.getLogger(LinkedNode.class);
public LinkedNode() {
head = null;
}
public Node head;//头节点
public int size = 1;
//头插法
public void add(int id) {
Node node = new Node(id);
node.next = head;
head = node;
size++;
}
//尾插法
public void endAdd(int id) {
Node node = new Node(id);
//获取链表最后一个节点
Node endNode = search(size);
//将新节点指到尾节点
endNode.next = node;
}
//查找链表中的某个位置元素
public Node search(int key) {
if(size<key) {
logger.debug("indexoutofboundsexception");
}
Node sNode = head;
for(int i=1;i<key;i++) {
sNode = sNode.next;
}
return sNode;
}
//删除某个位置的元素
public void del(LinkedNode linked,int key) {
//首先获取要删除元素的前一个元素
Node BeforNode = linked.search(key+1);
//获取要删除的元素
Node node = linked.search(key);
//将指针指向下一个元素
BeforNode.next = node.next;
//修改长度
size--;
}
//删除重复元素
public void delDulp() {
//使用Map的key值不重复原则
Map map = new HashMap();
//添加head
map.put(head.data, "value");
//存储前一个节点
Node BeforNode = head;
//当前处理节点
Node rNode = head;
//是否存在下一个节点
while(rNode.next!=null) {
rNode = rNode.next;
if(map.get(rNode.data)!=null) {
logger.debug(rNode.data+"重复");
//将前一个节点指针指向下一个节点
BeforNode.next = rNode.next;
//修改长度
size--;
}else {
logger.debug("处理节点"+rNode.data);
map.put(rNode.data, "value");
}
BeforNode = rNode;
}
}
//链表反转
public LinkedNode reverse(LinkedNode linked) {
//定义反转后的链表
LinkedNode reLinkedNode = new LinkedNode();
reLinkedNode.head = linked.head;
Node node = linked.head;
while(node.next!=null) {
//中间采用头插入法
}
return reLinkedNode;
}
//查找链表的中间节点
public void searchMiddle() {
//定义一次查询单节点
Node firstNode = head;
//定义一次查询双节点
Node sendcondNode = head;
//对于节点数为单数的链表,需判断next是否为空,否则再next会报空指针异常
while(sendcondNode.next!=null&&sendcondNode.next.next!=null) {
firstNode = firstNode.next;
sendcondNode = sendcondNode.next.next;
}
//当读取双节点的指针到队尾的时候,单节点指针刚好到链表一半
logger.debug(firstNode.data);
}
//判断链表是否有环
public void isCircleLinked() {
//定义一个慢节点
Node slowNode = head;
//定义一个快节点
Node fastNode = head;
//定义环入口节点
Node circleNode = null;
//环长度
int size = 0;
//当存在尾节点为空证明不存在环,只有存在环,快慢节点进入环后会无限循环
while(fastNode.next!=null&&fastNode.next.next!=null) {
slowNode = slowNode.next;
fastNode = fastNode.next.next;
if(slowNode==fastNode) {
//两个节点在环上不同速跑圈,两个节点必然相遇,相遇节点即为环入口
circleNode = slowNode;
//再次定义临时节点为环入口节点
Node cNode = slowNode.next;
while(cNode!=circleNode) {
cNode = cNode.next;
size++;
}
//环链表处理结束,加上环入口节点,跳出循环
size++;
break;
}
}
if(size>0) {
logger.debug("此链表有环,环长度为:"+size+",环入口节点值为:"+circleNode.data);
}
}
}