1、判断当前单链表是否有环?如果有,需要返回环的入口节点,再返回环的节点个数。
- 解决方案:首先判断是否有环,需要使用两个指针(java里面虽然没有指针,但是方法是一样的),一个为pfast,一个为pslow。pslow每次向前走一步,pfast每次向前走两步,若在某个时候pfast等于pslow,则存在环。到这里肯定会有疑问,如果有环它们两个一定会相遇么?难道不存在快的把慢的越过去,导致它们相遇不了。答案是它们一定会相遇,如果快的把慢的越过去了,只能说明它们已经相遇过了。我们可以这样分析假设它们有环,如果它们相遇,肯是pfast已经第二次入环了,这是pfast肯定在pslow的后面,pfast每次都会移动两步,而pslow每次移动一步,也就是说每次快的和慢的之间的距离都会减1,所以它们一定会相遇。
- 寻找入口节点,这个重点是一个定理:从相遇点到环入口节点的距离一定等于环的头节点到入口节点的距离。下面证明一下:
pslow走到相遇节点处,走的距离为x+y,而pfast却走了2(x+y),从相遇点到环入口节点的距离为2(x+y)-n+(n-x-y)=x即环的头节点到入口节点的距离,所以证明完成。
- 节点个数为从入口节点再走一圈。
2、判断单链表是否相交?如果相交的话,返回交点的节点。 - 解决方案1:首先判断不相交的情况:如果一有环一个无环,它们一定不会相交。然后对两个都有环的情况来说,两个单链表的环的大小肯定都一样,主要看链表头结点到环入口节点的长度,然后计算它们的长度差c,再让长度长的先走c步。然后短的开始走,等他们节点相等时就证明它们相交,那么相交节点也就找到!如果它们都没环,也是取它们整个长度的差值c.剩下的同上。
- 解决方案2:把其中一个链表的所有节点的指针域都置为null,然后遍历下个链表,如果下个链表还未到尾节点指针域就有null,则它们相交。
3、寻找倒数第K个节点 没有返回null。 - 解决方案1:设置两个指针,一个先走k步另一个开始走,当先走那个的next为空时,另一个就在倒数第k个节点。
- 解决方案2:先用一个指针求出链表的节点个数num,然后用新指针走num-k步。
java代码实现
class Node{
int value;
Node next;
Node(){
this(0);
}
Node(int value){
this.value= value;
this.next = null;
}
}
class LinkList{
Node head;
public LinkList(){
this.head = new Node();
}
public boolean empty(){
return head==null;
}
public void insertHead(int value){
Node node = new Node(value);
node. next = head;
head = node;
}
public void insertTail(int value){
Node ptail = head;
while(ptail.next != null){
ptail = ptail.next;
}
ptail.next = new Node(value);
}
public void destroy(int value){
Node pcur = head.next;
Node ppre = head;
while(pcur != null){
if(pcur.value == value){
ppre.next = pcur.next;
break;
}
ppre = pcur;
pcur = pcur.next;
}
}
//创建环链表
public void CreateCircle(int k){
Node ptail = head;
while(ptail.next != null){
ptail = ptail.next;
}
ptail.next=findReverseKNode(k);
}
//判断当前单链表是否有环 true:有环 false:没有环
public boolean HaveCircle(){
Node pfast = this.head;
Node pslow = this.head;
while(pfast.next!=null){
pfast=pfast.next.next;
pslow=pslow.next;
if(pfast==pslow)
return true;
}
return false;
}
//判断单链表是否有环,如果有,需要返回环的入口节点
public Node firstCircleNode(){
Node pfast = this.head;
Node pslow = this.head;
while(pfast.next!=null){
pfast=pfast.next.next;
pslow=pslow.next;
if(pfast==pslow){
pfast = head;
while(pfast!=pslow){
pfast=pfast.next;
pslow=pslow.next;
}
return pfast;
}
}
return null;
}
//判断单链表是否有环,如果有,返回环的节点个数
public int getCircleNodeNum(){
Node pfast = head;
Node pslow = head;
while(pfast.next!=null){
pfast=pfast.next.next;
pslow=pslow.next;
if(pfast==pslow){
pfast = head;
while(pfast!=pslow){
pfast=pfast.next;
pslow=pslow.next;
}
int Num=0;
while(pfast!=pslow.next){
Num++;
pslow=pslow.next;
}
return Num;
}
}
return 0;
}
//创相交链表
public void CreatLinkCross(LinkList list,int k){
Node pnode1 = this.head;
Node pnode2 = list.head;
while(pnode2.next!=null){
pnode2=pnode2.next;
}
for(int i=0;i<k;i++){
pnode1=pnode1.next;
}
pnode2.next=pnode1;
}
//判断单链表是否相交 true:相交 false:不相交
public boolean isLinkCross(LinkList list){
if (this.empty() || list.empty())
return false;// 两个链表为空它们不相交
if (!(this.HaveCircle() || list.HaveCircle())) {
Node pnode1 = this.head;
Node pnode2 = list.head;
while (pnode1.next != null) {
pnode1 = pnode1.next;
}
while (pnode2.next != null) {
pnode2 = pnode2.next;
}
if (pnode1 == pnode2){
return true;// 两个无环单链表,最后一个结点相同时,它们相交
}
else{
return false;
}
}
else if (this.HaveCircle()&&list.HaveCircle()) {
if (firstCircleNode() ==firstCircleNode()){
return true;// 两个有环单链表,它们环的入口结点相同时,它们相交
}
else{
return false;
}
}
else {
return false;// 两个单链表,一个有环,一个无环,它们一定不相交
}
}
//如果相交的话,返回交点的节点
public Node getLinkCrossNode(LinkList list){
if (this.isLinkCross(list)){
if (!this.HaveCircle()) //如果list1没有环,则list2也没有
{
int Lcount1 = 1;// 单链表list1中结点的个数
int Lcount2 = 1;// 单链表list中结点的个数
Node pnode1 = this.head;
Node pnode2 = list.head;
while (pnode1.next != null) {
pnode1= pnode1.next;
Lcount1++;
}
while (pnode2.next != null) {
pnode2= pnode2.next;
Lcount2++;
}
if (Lcount1 >= Lcount2)// 单链表list1比单链表list2长或两者一样长时
{
int Count = Lcount1 - Lcount2;// 单链表list1比单链表list2多出的结点的个数
pnode1= this.head;
pnode2 = list.head;
while (Count > 0) {
pnode1= pnode1.next;
}
while (pnode1 != null) {
if (pnode1==pnode2)
return pnode1;
pnode1= pnode1.next;
pnode2 = pnode2.next;
}
}
else {
int Count2 = Lcount2 - Lcount1;// 单链表L2比单链表L1多出的结点的个数
pnode1= this.head;
pnode2 = list.head;
while (Count2 > 0) {
pnode2 = pnode2.next;
}
while (pnode2!= null) {
if (pnode1 == pnode2)
return pnode1;
pnode1= pnode1.next;
pnode2 =pnode2.next;
}
}
}
else // list1有环时,此时list1与list2都有环
{
int Lcount1 = 1;// 单链表list1中从头结点到环的入口结点之间所有结点的个数,包括头结点与环的入口结点
int Lcount2 = 1;// 单链表list2中从头结点到环的入口结点之间所有结点的个数,包括头结点与环的入口结点
Node pnode1 = this.head;
Node pnode2 = list.head;
while (pnode1 != firstCircleNode()) {
pnode1 = pnode1.next;
Lcount1++;
}
while (pnode2!= firstCircleNode()) {
pnode2= pnode2.next;
Lcount2++;
}
if (Lcount1 >= Lcount2)// 单链表list1比单链表list2从头结点到环的入口结点之间所有结点的个数长或两者一样长时
{
int Count3 = Lcount1 - Lcount2;// 单链表list1比单链表list2从头结点到环的入口结点之间所有结点的个数多出的结点的个数
pnode1 = this.head;
pnode2 = list.head;
while (Count3 > 0) {
pnode1 = pnode1.next;
}
while (pnode1 != null) {
if (pnode1== pnode2)
return pnode1;
pnode1 = pnode1.next;
pnode2 = pnode2.next;
}
}
else {
int Count4 = Lcount2 -Lcount1;// 单链表list2比单链表list1从头结点到环的入口结点之间所有结点的个数多出的结点的个数
pnode1 = this.head;
pnode2 = list.head;
while (Count4 > 0) {
pnode2= pnode2.next;
}
while (pnode2!= null) {
if (pnode1== pnode2)
return pnode1;
pnode1 = pnode1.next;
pnode2= pnode2.next;
}
}
}
}
return null;
}
//寻找倒数第K个节点 没有返回null
public Node findReverseKNode(int k){
Node pnode=this.head;
if (empty())
{
return null;
}
int length=0;
while(pnode.next!=null){
length++;
pnode=pnode.next;
}
if (k==0||k>length)
{
return null;
}
pnode=this.head;
for (int i=0;i<length-k;i++)
{
pnode=pnode.next;
}
return pnode;
}
public String toString(){
StringBuilder builder=new StringBuilder();
Node n=head;
while(n.next!=null){
builder.append(n.value +" ");
n=n.next;
}
return builder.toString();
}
}
public class TestLinkListDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkList q1 = new LinkList();
for (int i=0; i<20; i++ ){
q1.insertHead((int)(Math.random()*100));
}
System.out.println(q1.toString());
System.out.println(q1.findReverseKNode(5).value);
q1.CreateCircle(5);
//System.out.println(q1.toString());
System.out.println(q1.HaveCircle());
if(q1.HaveCircle()){
System.out.println(q1.firstCircleNode().value);
System.out.println(q1.getCircleNodeNum());
}
LinkList q2= new LinkList();
for (int i=0; i<5; i++ ){
q2.insertHead((int)(Math.random()*100));
}
System.out.println(q2.toString());
q1.CreatLinkCross(q2,6);
System.out.println(q1.isLinkCross(q2));
if(q1.isLinkCross(q2)){
System.out.println(q1.getLinkCrossNode(q2).value);
}
}
}
- 本人写这篇博客主要是因为前两天写了一篇关于栈的博客,里面简单介绍了一下单链表,而这次想着把单链表问题完善一下!如有错误,还望指正!