题目
1.逆序输出链表
1->2->3->4->5
print() 5 4 3 2 1
2.逆置链表
1->2->3->4->5
reverse() 5->4->3->2->1
3.查找单链表中倒数第K个元素
4.合并两个有序的单链表,保证合并后的依然有序
5.不允许遍历链表, 在 pos之前插入
6.找两条相交链表的相交节点
7.判断链表是否有环,有环输出环的入口节点,无环返回null
题目分析与实现
1.使用递归的方法实现。
public static <T extends Comparable<T>> void reversePrint(MySingleLinkedList<T>.Node<T> tmp){
//给出终止条件
if(tmp == null){
//满足终止条件时的解决办法
return;
}
//相同的逻辑
reversePrint(tmp.next);
System.out.println(tmp);
}
2.设置三个指针分别指向前驱,结点,和后继。
//逆置链表
public static <T extends Comparable<T>> MySingleLinkedList<T>.Node<T> reverse(MySingleLinkedList<T>.Node<T> head){
MySingleLinkedList<T>.Node<T> current = head;
MySingleLinkedList<T>.Node<T> prev = null;
MySingleLinkedList<T>.Node<T> next = null;
MySingleLinkedList<T>.Node<T> newHead = null;
while(current != null){
next = current.next;
if(next == null){
newHead = current;
}
//改变current和prev之间的指向
current.next = prev;
//让prev、current往后走
prev = current;
current = next;
}
return newHead;
}
3.使用两个指针,两个指针的距离为k,当快指针达到结尾,慢指针则指向目标节点
// 查询倒数第k个元素
public T InverseQuery(int k){
if(head==null||k<0){
return null;
}
//遍历得到链表元素数
int count=0;
Node<T> tmp1=head;
Node<T> tmp2=head;
while (tmp1!=null) {
tmp1=tmp1.next;
if(count==k){
tmp2=tmp2.next;
k++;
}
count++;
}return tmp2.data;
4.使用两个指针分别指向两条链表,然后比较两个指针的data域指针进行相应移动
public <T extends Comparable<T>>MySingleLinkedList<T>.Node<T> combine(MySingleLinkedList<T>.Node<T> head1,MySingleLinkedList<T>.Node<T> head2){
MySingleLinkedList<T>.Node<T> tmp1=head1;
MySingleLinkedList<T>.Node<T> tmp2=head2;
MySingleLinkedList<T>.Node<T> current =null;
MySingleLinkedList<T>.Node<T> newHead =null;
while (true) {
if (tmp1.data.compareTo(tmp2.data)>0) {
current=tmp2;
tmp2=tmp2.next;
}else {
current=tmp1;
tmp1=tmp1.next;
}
if(tmp1==null){
current.next=tmp2;
break;
}else if(tmp2==null){
current.next=tmp1;
break;
}
}return newHead;
}
5.现在pos后插入结点再交换他们的数据域则实现前插入
public boolean insert(MySingleLinkedList<T> list ,MySingleLinkedList<T>.Node<T> pos,Node<T> node ){
if(pos==null){
return false;
}
//在pos后插入
node.next=pos.next;
pos.next=node;
//交换数据
node.data=pos.data;
return true;
}
6.(1)可以借助栈进行实现结点顺序倒置,然后出栈比较,如果两个栈的栈顶元素不同则上次出栈的元素则为相交节点
public static <T extends Comparable<T>> MySingleLinkedList<T>.Node<T> crosspoint(MySingleLinkedList<T> list1,MySingleLinkedList<T> list2){
Stack stack1= new Stack();
Stack stack2= new Stack();
MySingleLinkedList<T>.Node<T> tmp1=list1.head;
MySingleLinkedList<T>.Node<T> tmp2=list2.head;
MySingleLinkedList<T>.Node<T> node=null;
//所有节点入栈
while (tmp1!=null){
stack1.push(tmp1);
tmp1=tmp1.next;
}
while (tmp2!=null){
stack2.push(tmp2);
tmp2=tmp2.next;
}
//出栈比较
while (!stack1.empty()||!stack2.empty()){
if(stack1.peek()==stack2.peek()){
node=(MySingleLinkedList<T>.Node<T>) stack1.peek();
stack1.pop();
stack2.pop();
}else{
return node;
}
}return null;
}
(2)同样可以使用快慢指针,让长链表使用快指针,短链表使用慢指针,当两个长度相同时,两个指针一起走,知道遇到目标节点。
public <T extends Comparable<T>> MySingleLinkedList<T>.Node<T> crosspoint(MySingleLinkedList<T> list1,MySingleLinkedList<T> list2){
MySingleLinkedList<T>.Node<T> tmp1=list1.head;
MySingleLinkedList<T>.Node<T> tmp2=list2.head;
int count1=0;//记录list1长度
int count2=0;//记录list2长度
while (tmp1!=null){
tmp1=tmp1.next;
count1++;
}
while (tmp2!=null){
tmp2=tmp2.next;
count2++;
}
tmp1=list1.head;//重置指针
tmp2=list2.head;
if(count1>count2){//让长链表的指针先走
while (tmp1!=tmp2){//两个未遍历的链表长度相同,慢指针开始走
tmp1=tmp1.next;
if(count1==count2){
tmp2=tmp2.next;
count2--;
}
count1--;
}
}else {
while (tmp1!=tmp2){
tmp2=tmp2.next;
if(count1==count2){
tmp1=tmp1.next;
count1--;
}
count2--;
}
}return tmp1;
}
7.借助数组对已经遍历过的结点存储然后,和后面遍历的结点比较,如果后面遍历的结点在数组中,则此结点为循环的入口结点。
public <T extends Comparable<T>> MySingleLinkedList<T>.Node<T> containRing( MySingleLinkedList<T>.Node<T> head){
MySingleLinkedList<T>.Node<T> tamp=head;
MyarrayList<MySingleLinkedList<T>.Node<T>> arr=new MyarrayList();
//数组存储,此处调用了自己的数组类进行存储。也可以用调用系统数组类
//ArrayList<MySingleLinkedList<T>.Node<T>> arr=new ArrayList<>();
while (!arr.contains(tamp)){
arr.addTail(tamp);//存进数组
tamp=tamp.next;
if(tamp==null){return null;}//无环返回null
}return tamp;
}