1.实现一个链表
public class Linked {
public Node first;
public Node last;
//头插
public void addFirst(int data){
//获取原头节点
Node f = first;
//创建新节点
Node newNode = new Node(data);
//指向新头节点
first = newNode;
//
if(f == null){
last = newNode;
}else {
newNode.next = f;
}
}
//尾插法
public void addLast(int data){
//创建新节点
Node newNode = new Node(data);
//将原头节点存入
Node l = last;
//指向新头节点
last = newNode;
if(l == null){
first = newNode;
}else {
//新头节点指向原头节点
l.next = newNode;
}
}
public void addNode(Node node){
//获取尾节点
Node l = last;
//更新尾节点
last = node;
if(l == null){
first = node;
}else {
//指向尾节点
l.next = node;
}
}
static class Node<E>{
int item;
Node next;
public Node(int data){
item = data;
}
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
for(Node n = first; n != null;n = n.next){
sb.append(n.item);
if(n.next != null){
sb.append("->");
}
}
return sb.toString();
}
}
2.合并有序链表
//运用双指针合并
public static Linked mgar(Linked l1,Linked l2){
Linked result = new Linked();
//创建引用
Linked.Node p1 = l1.first,p2 = l2.first;
while (p1 != null || p2 != null){
if (p1 == null){
result.addLast(p2.item);
p2 = p2.next;
continue;
}
if (p2 == null){
result.addLast(p1.item);
p1 = p1.next;
continue;
}
if(p1.item < p2.item){
result.addLast(p1.item);
p1 = p1.next;
}else {
result.addLast(p2.item);
p2 = p2.next;
}
}
return result;
}
测试代码:
public static void main(String[] args) {
Linked linked1 = new Linked();
Linked linked2 = new Linked();
linked1.addLast(2);
linked1.addLast(4);
linked1.addLast(6);
linked1.addLast(10);
linked1.addLast(11);
System.out.println(linked1);
linked2.addLast(1);
linked2.addLast(3);
linked2.addLast(9);
linked2.addLast(13);
System.out.println(linked2);
System.out.println(mgar(linked1,linked2));
}
3.反转链表
栈具有后进先出的特点,所以可以借助栈实现
public static void main(String[] args) {
Linked linked = new Linked();
linked.addLast(1);
linked.addLast(3);
linked.addLast(5);
linked.addLast(7);
System.out.println(linked);
Linked ret = fan(linked);
System.out.println(ret);
}
public static Linked fan(Linked l){
//创建栈
Stack<Linked.Node> stack = new Stack<>();
//遍历链表并存入栈、
for(Linked.Node n = l.first;n != null; n = n.next){
stack.add(n);
}
//清空当前链表
l = new Linked();
//获取栈元素插入链表
while (!stack.isEmpty()){
l.addLast(stack.pop().item);
}
return l;
}
4.判断链表是否有环
方法一 使用set集合
set集合内元素唯一,通过Set集合记录值的方式,如果有重复的数据,就代表有环。
public static boolean hasCycle1(Linked.Node node){
//创建Set
Set<Linked.Node> set = new HashSet<>();
while (node != null){
//判断set中是否存在该节点
if(set.contains(node)){
return true;
}
//不存在则添加
set.add(node);
//移动节点
node = node.next;
}
return false;
}
方法二 使用快慢指针方法
定义两个指针:快指针fast和慢指针slow。在开始遍历前,两个指针都指向链表头head,然后在每一次循环操作中,慢指针slow每次向前一步,而快指针fast每次向前两步。
由于fast要比slow移动的快,如果有环,fast一定会先进入环,而slow后进入环。当两个指针都进入环之后,经过若干步的操作之后二者一定能够在环上相遇。
public static boolean hasCycle2(Linked.Node node){
//空链表则一定无环
if(node == null){
return false;
}
//定义快慢指针
Linked.Node fast = node,slow = node;
//如果快慢指针都指向null,说明循环遍历结束无环跳出循环
while (fast != null && fast.next != null && slow != null){
//移动指针,快的走两步,慢的走一步
fast = fast.next.next;
slow = slow.next;
//如果相同则快指针在环中追上了慢指针
if(fast == slow){
return true;
}
}
return false;
}