数据结构和算法经典100题-第7题
2015-04-21 01:36
218 查看
题目要求
微软亚院之编程判断俩个链表是否相交
给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。
问题扩展:
1.如果链表可能有环列?
2.如果需要求出俩个链表相交的第一个节点列?
问题分析:
其实本题目是考察链表的相交和环的问题。
一个链表的相交判断中,带环和不带环的判断方法是不一样的。稍后介绍两个都带环链表和都不带环链表的相交的判断方法。
于是此问题就分解为了3个:
如何判断一条链表是否带环?
如何判断两条不带环链表是否相交?
如何判断两条带环的链表是否相交?
如何判断一条链表是否带环?
那么我们先解决如何判断一条链表是否带环的问题。
一般解决判断链表是否有环问题的方法都是设置两个指针p1和p2,p1和p2分别在链表每次移动1步和2步,若最终相遇,则说明链表有环;若p2指向空,则说明无环。
稍微引申一下,如何返还链表的环开始所在的结点。这里涉及到一个公式推导:
假设单链表的总长度为L,头结点到环入口的距离为a,环入口到p1,p2指针相遇的结点距离为x,环的长度为r,p1总共走了s步,则p2走了2s步。另外,p2要追上p1的话,p2至少要在环里面转了一圈多(假设转了n圈加x的距离),得到以下关系:
s = a + x;
2s = a + nr + x;
=>a + x = nr;
=>a = nr - x;
由上式可知:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点.
那么我们看一下代码实现:
如何判断两条不带环链表是否相交?
通常判断两条不带环的链表相交有两种方法:
利用无环单链表相交的冲要条件:两条无环链表的尾结点一定相交。
假设两无环链表分别是L1和L2,把L2头结点接到L1的尾结点,判断L1是否有环。
这里我给出第二种方法的代码实现:
如何判断两条都带环的链表是否相交?
这里利用一个充分必要条件:若两条都带环的链表相交,则其中任意一条链表的环所处的结点,必然在与其相交的链表上。
这样就将判断两条都带环的链表的相交问题转化为:
求出一条链表的环结点;
求该环结点是否在另一条链表上。
下面我们看一下代码实现:
ok,解决完以上三个问题,我们继续看我们的题目,那么很容易的就将此问题分解成4个步骤:
判断两条链表是否都由环?
若都有环,则调用都有环的判断相交问题的方法;
若都无环,则调用都无环的判断相交问题的方法;
若一条有环,一条无环,则说明此两条链表不可能相交。
那么我们看一下相关的代码实现:
为了验证这个问题,我写了一个测试程序,代码如下:
经过测试程序测试,以上代码能够跑通。下面是解决这个题目的完整版的代码。
先看头文件:
再看一下源码实现和测试程序
最后看一下主函数
Okay,第7题的完整解题过程就到这里了,希望大家多指教。
路漫漫其修远兮,吾将上下而…
微软亚院之编程判断俩个链表是否相交
给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。
问题扩展:
1.如果链表可能有环列?
2.如果需要求出俩个链表相交的第一个节点列?
问题分析:
其实本题目是考察链表的相交和环的问题。
一个链表的相交判断中,带环和不带环的判断方法是不一样的。稍后介绍两个都带环链表和都不带环链表的相交的判断方法。
于是此问题就分解为了3个:
如何判断一条链表是否带环?
如何判断两条不带环链表是否相交?
如何判断两条带环的链表是否相交?
如何判断一条链表是否带环?
那么我们先解决如何判断一条链表是否带环的问题。
一般解决判断链表是否有环问题的方法都是设置两个指针p1和p2,p1和p2分别在链表每次移动1步和2步,若最终相遇,则说明链表有环;若p2指向空,则说明无环。
稍微引申一下,如何返还链表的环开始所在的结点。这里涉及到一个公式推导:
假设单链表的总长度为L,头结点到环入口的距离为a,环入口到p1,p2指针相遇的结点距离为x,环的长度为r,p1总共走了s步,则p2走了2s步。另外,p2要追上p1的话,p2至少要在环里面转了一圈多(假设转了n圈加x的距离),得到以下关系:
s = a + x;
2s = a + nr + x;
=>a + x = nr;
=>a = nr - x;
由上式可知:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点.
那么我们看一下代码实现:
node* DoubleListOfCrossing::isCircle(node * head) { if (NULL == head) { return NULL; } node* p1 = head; node* p2 = head; do { if (NULL != p1->next && NULL != p2->next && NULL != p2->next->next) { p1 = p1->next; p2 = p2->next->next; } else { return NULL; } }while (p1 != p2); p2 = head; while (p1 != p2) { p1 = p1->next; p2 = p2->next; } return p1; }
如何判断两条不带环链表是否相交?
通常判断两条不带环的链表相交有两种方法:
利用无环单链表相交的冲要条件:两条无环链表的尾结点一定相交。
假设两无环链表分别是L1和L2,把L2头结点接到L1的尾结点,判断L1是否有环。
这里我给出第二种方法的代码实现:
/* 不带环的情况下判断两个链表是否相交 */ bool DoubleListOfCrossing::isCrossingOfNoCircle() { if (NULL == m_h1 || NULL == m_h2) { return NULL; } /* 把链表2接到链表1上. */ node * tail1 = m_h1; while (NULL != tail1->next) { tail1 = tail1->next; } tail1->next = m_h2; return (NULL == isCircle(m_h1)) ? false : true; }
如何判断两条都带环的链表是否相交?
这里利用一个充分必要条件:若两条都带环的链表相交,则其中任意一条链表的环所处的结点,必然在与其相交的链表上。
这样就将判断两条都带环的链表的相交问题转化为:
求出一条链表的环结点;
求该环结点是否在另一条链表上。
下面我们看一下代码实现:
node* DoubleListOfCrossing::findCircleNode(node * head) { return isCircle(head); } /* 判断一个结点是否在链表上. */ bool DoubleListOfCrossing::isExist(node* head,node * element) { if (NULL == head) { return false; } node * tmp = head; while (NULL != tmp->next) { if (tmp == element) { return true; } else { tmp = tmp->next; } } return false; } /* 两个链表都带环的情况下,判断第一个链表的环结点是否在第二个链表上 */ bool DoubleListOfCrossing::isCrossingOfCircle() { node * cross = findCircleNode(m_h1); return isExist(m_h2, cross); }
ok,解决完以上三个问题,我们继续看我们的题目,那么很容易的就将此问题分解成4个步骤:
判断两条链表是否都由环?
若都有环,则调用都有环的判断相交问题的方法;
若都无环,则调用都无环的判断相交问题的方法;
若一条有环,一条无环,则说明此两条链表不可能相交。
那么我们看一下相关的代码实现:
bool DoubleListOfCrossing::isCrossing() { #define IS_CIRCLE(a) NULL != isCircle((a)) #define NOT_CIRCLE(a) NULL == isCircle((a)) if (NULL == m_h1 && NULL == m_h2) { cout<<"NULL == m_h1 && NULL == m_h2"<<endl; return false; } bool bothNotCircle = (NOT_CIRCLE(m_h1) && NOT_CIRCLE(m_h2)) ? true : false; bool bothCircle = (IS_CIRCLE(m_h1) && IS_CIRCLE(m_h2)) ? true : false; /* 判断两个链表是否都有环,若都没有环 */ if (bothNotCircle) { return isCrossingOfNoCircle(); } /* 若都有环 */ if (bothCircle) { return isCrossingOfCircle(); } /* 若一个有环,一个没有环则两个链表不可能相交 */ return false; }
为了验证这个问题,我写了一个测试程序,代码如下:
node* initOneNode(valueType value) { node* tmp = (node*)malloc(sizeof(node)); memset(tmp, 0, sizeof(node)); tmp->value = value; return tmp; } /* 初始化一个有环的链表,返回链表头结点指针 */ node* initOneCircleList(int size,int crossPosition) { node *array[size]; node * prev = NULL; for (int i = 0; i < size; i++) { array[i] = initOneNode(i); //cout<<"initOneCircleList value:"<<array[i]->value<<endl; //cout<<"initOneCircleList address:"<<array[i]<<endl; if (NULL != prev) { prev->next = array[i]; } prev = array[i]; //cout<<"prev address:"<<prev<<endl; } array[size-1]->next = array[crossPosition-1]; #if 0 node * tmp = array[0]; for (int i = 0; i < size*2; i++) { cout<<"array["<<i<<"] address:"<<tmp<<endl; tmp = tmp->next; } #endif return array[0]; } /* 初始化一个有环的链表,返回链表头结点指针 */ node* initOneNoCircleList(int size) { node* tmp = NULL; node* prev = initOneNode(0); node* head = prev; for (int i = 1; i < size; i++) { tmp = initOneNode(i); prev->next = tmp; prev = tmp; } #if 0 tmp = head; for (int i = 0; i < size; i++) { cout<<"tmp address:"<<tmp<<endl; tmp = tmp->next; } #endif return head; } /* 测试两条有环不相交链表 */ int test_case_2(node* h1, node* h2) { h1 = initOneCircleList(5, 3); h2 = initOneCircleList(5, 3); return 0; } /* 测试两条无环相交链表 */ int test_case_3(node* h1, node* h2) { h1 = initOneNoCircleList(5); h2 = initOneNoCircleList(4); node* tmp = h2; while (NULL != tmp->next) { tmp = tmp->next; } tmp->next = h1; return 0; } /* 测试两条无环不相交链表 */ int test_case_4(node* h1, node* h2) { h1 = initOneNoCircleList(5); h2 = initOneNoCircleList(4); return 0; } /* 测试两条有环相交链表 */ int test_case_1(node** h1,node** h2) { *h1 = initOneCircleList(5, 3); *h2 = initOneNoCircleList(3); node* tmp_1 = *h1; node* tmp_2 = *h2; while (NULL != tmp_2->next) { // cout<<"tmp_1 address:"<<tmp_1<<endl; // cout<<"tmp_2 address:"<<tmp_2<<endl; tmp_1 = tmp_1->next; tmp_2 = tmp_2->next; } tmp_2->next = tmp_1; #if 0 tmp_1 = h1; tmp_2 = h2; for(int i = 0; i < 5*2; i++) { cout<<"tmp_1 address:"<<tmp_1<<endl; cout<<"tmp_2 address:"<<tmp_2<<endl; tmp_1 = tmp_1->next; tmp_2 = tmp_2->next; } #endif cout<<"h1:"<<*h1<<" h2:"<<*h2<<endl; return 0; } int test_7() { node *h1 = NULL; node *h2 = NULL; test_case_1(&h1, &h2); //test_case_2(h1, h2); //test_case_3(h1, h2); //test_case_4(h1, h2); cout<<"h1 address:"<<h1<<" h2 address:"<<h2<<endl; DoubleListOfCrossing obj(h1,h2); if ( obj.isCrossing()) cout<<"list h1 & h2 is crossing."<<endl; else cout<<"list h1 & h2 is not crossing"<<endl; return 0; } int main(int argc, const char * argv[]) { //test_1(); //test_2(); //test_3(); //test_4(); //maxHeap_test(); //test_5_1(); test_7(); return 0; }
经过测试程序测试,以上代码能够跑通。下面是解决这个题目的完整版的代码。
先看头文件:
// // 7th.h // 100-alg-tests // // Created by bobkentt on 15-4-11. // Copyright (c) 2015年 kedong. All rights reserved. // #ifndef ___00_alg_tests___th__ #define ___00_alg_tests___th__ #include <stdio.h> #define valueType int struct node { valueType value; node * next; }; class DoubleListOfCrossing { /* 判断一个链表是否有环 */ node* isCircle(node * head); /// 判断两个链表是否相交 bool isCrossingOfNoCircle(); bool isCrossingOfCircle(); /* 找到一个带环链表的环结点. */ node* findCircleNode(node * head); bool isExist(node* head,node * element); node * m_h1; node * m_h2; public: DoubleListOfCrossing(node * h1, node * h2) { m_h1 = h1;m_h2 = h2;}; ~DoubleListOfCrossing() {}; bool isCrossing(); /* @type == 1 print m_h1;@type==2 print m_h2 */ void printList(bool type); }; // 测试程序 int test_7(); #endif /* defined(___00_alg_tests___th__) */
再看一下源码实现和测试程序
//
// 7th.cpp
// 100-alg-tests
//
// Created by bobkentt on 15-4-11.
// Copyright (c) 2015年 kedong. All rights reserved.
//
#include <iostream>
#include <stdlib.h>
#include "7th.h"
using namespace std;
/*题目要求:
微软亚院之编程判断俩个链表是否相交
给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。
问题扩展:
1.如果链表可能有环列?
2.如果需要求出俩个链表相交的第一个节点列?
*/
/// 判断一个链表是否有环
/*
假设单链表的总长度为L,头结点到环入口的距离为a,
环入口到快慢指针相遇的结点距离为x,环的长度为r,
慢指针总共走了s步,则快指针走了2s步。另外,
快指针要追上慢指针的话快指针至少要在环里面转了
一圈多(假设转了n圈加x的距离),得到以下关系:
s = a + x;
2s = a + nr + x;
=>a + x = nr;
=>a = nr - x;
由上式可知:若在头结点和相遇结点分别设一指针,
同步(单步)前进,则最后一定相遇在环入口结点.
*/
/*判断链表是否有环,如果有环则返回环的首结点指针,否则返回NULL值*/
node* DoubleListOfCrossing::isCircle(node * head) { if (NULL == head) { return NULL; } node* p1 = head; node* p2 = head; do { if (NULL != p1->next && NULL != p2->next && NULL != p2->next->next) { p1 = p1->next; p2 = p2->next->next; } else { return NULL; } }while (p1 != p2); p2 = head; while (p1 != p2) { p1 = p1->next; p2 = p2->next; } return p1; }
node* DoubleListOfCrossing::findCircleNode(node * head) {
return isCircle(head);
}
/* 不带环的情况下判断两个链表是否相交 */ bool DoubleListOfCrossing::isCrossingOfNoCircle() { if (NULL == m_h1 || NULL == m_h2) { return NULL; } /* 把链表2接到链表1上. */ node * tail1 = m_h1; while (NULL != tail1->next) { tail1 = tail1->next; } tail1->next = m_h2; return (NULL == isCircle(m_h1)) ? false : true; }
/* 判断一个结点是否在链表上. */
bool DoubleListOfCrossing::isExist(node* head,node * element) {
if (NULL == head) {
return false;
}
node * tmp = head;
while (NULL != tmp->next) {
if (tmp == element) {
return true;
} else {
tmp = tmp->next;
}
}
return false;
}
/* 两个链表都带环的情况下,判断第一个链表的环结点是否在第二个链表上 */
bool DoubleListOfCrossing::isCrossingOfCircle() {
node * cross = findCircleNode(m_h1);
return isExist(m_h2, cross);
}
/*
* @param <type> <true> 打印链表1;
* <false>打印链表2.
*/
void DoubleListOfCrossing::printList(bool type) {
node * tail = (true == type) ? m_h1 : m_h2;
if (NULL == tail) {
return;
}
while (NULL != tail->next) {
cout<<tail->value<<" ";
tail = tail->next;
}
cout<<endl;
return;
}
bool DoubleListOfCrossing::isCrossing() { #define IS_CIRCLE(a) NULL != isCircle((a)) #define NOT_CIRCLE(a) NULL == isCircle((a)) if (NULL == m_h1 && NULL == m_h2) { cout<<"NULL == m_h1 && NULL == m_h2"<<endl; return false; } bool bothNotCircle = (NOT_CIRCLE(m_h1) && NOT_CIRCLE(m_h2)) ? true : false; bool bothCircle = (IS_CIRCLE(m_h1) && IS_CIRCLE(m_h2)) ? true : false; /* 判断两个链表是否都有环,若都没有环 */ if (bothNotCircle) { return isCrossingOfNoCircle(); } /* 若都有环 */ if (bothCircle) { return isCrossingOfCircle(); } /* 若一个有环,一个没有环则两个链表不可能相交 */ return false; }
node* initOneNode(valueType value) {
node* tmp = (node*)malloc(sizeof(node));
memset(tmp, 0, sizeof(node));
tmp->value = value;
return tmp;
}
/* 初始化一个有环的链表,返回链表头结点指针 */
node* initOneCircleList(int size,int crossPosition) {
node *array[size];
node * prev = NULL;
for (int i = 0; i < size; i++) {
array[i] = initOneNode(i);
//cout<<"initOneCircleList value:"<<array[i]->value<<endl;
//cout<<"initOneCircleList address:"<<array[i]<<endl;
if (NULL != prev) {
prev->next = array[i];
}
prev = array[i];
//cout<<"prev address:"<<prev<<endl;
}
array[size-1]->next = array[crossPosition-1];
#if 0
node * tmp = array[0];
for (int i = 0; i < size*2; i++) {
cout<<"array["<<i<<"] address:"<<tmp<<endl;
tmp = tmp->next;
}
#endif
return array[0];
}
/* 初始化一个有环的链表,返回链表头结点指针 */
node* initOneNoCircleList(int size)
{
node* tmp = NULL;
node* prev = initOneNode(0);
node* head = prev;
for (int i = 1; i < size; i++) {
tmp = initOneNode(i);
prev->next = tmp;
prev = tmp;
}
#if 0
tmp = head;
for (int i = 0; i < size; i++) {
cout<<"tmp address:"<<tmp<<endl;
tmp = tmp->next;
}
#endif
return head;
}
/* 测试两条有环不相交链表 */
int test_case_2(node* h1, node* h2) {
h1 = initOneCircleList(5, 3);
h2 = initOneCircleList(5, 3);
return 0;
}
/* 测试两条无环相交链表 */
int test_case_3(node* h1, node* h2) {
h1 = initOneNoCircleList(5);
h2 = initOneNoCircleList(4);
node* tmp = h2;
while (NULL != tmp->next) {
tmp = tmp->next;
}
tmp->next = h1;
return 0;
}
/* 测试两条无环不相交链表 */
int test_case_4(node* h1, node* h2) {
h1 = initOneNoCircleList(5);
h2 = initOneNoCircleList(4);
return 0;
}
/* 测试两条有环相交链表 */
int test_case_1(node** h1,node** h2) {
*h1 = initOneCircleList(5, 3);
*h2 = initOneNoCircleList(3);
node* tmp_1 = *h1;
node* tmp_2 = *h2;
while (NULL != tmp_2->next) {
// cout<<"tmp_1 address:"<<tmp_1<<endl;
// cout<<"tmp_2 address:"<<tmp_2<<endl;
tmp_1 = tmp_1->next;
tmp_2 = tmp_2->next;
}
tmp_2->next = tmp_1;
#if 0
tmp_1 = h1;
tmp_2 = h2;
for(int i = 0; i < 5*2; i++) {
cout<<"tmp_1 address:"<<tmp_1<<endl;
cout<<"tmp_2 address:"<<tmp_2<<endl;
tmp_1 = tmp_1->next;
tmp_2 = tmp_2->next;
}
#endif
cout<<"h1:"<<*h1<<" h2:"<<*h2<<endl;
return 0;
}
int test_7() {
node *h1 = NULL;
node *h2 = NULL;
test_case_1(&h1, &h2);
//test_case_2(h1, h2);
//test_case_3(h1, h2);
//test_case_4(h1, h2);
cout<<"h1 address:"<<h1<<" h2 address:"<<h2<<endl;
DoubleListOfCrossing obj(h1,h2);
if ( obj.isCrossing())
cout<<"list h1 & h2 is crossing."<<endl;
else
cout<<"list h1 & h2 is not crossing"<<endl;
return 0;
}
最后看一下主函数
// // main.cpp // 100-alg-tests // // Created by bobkentt on 15-3-24. // Copyright (c) 2015年 kedong. All rights reserved. // #include <iostream> //#include "2th.h" //#include "3th.h" //#include "4th.h" //#include "maxHeap.h" //#include "5th.h" #include "7th.h" int main(int argc, const char * argv[]) { //test_1(); //test_2(); //test_3(); //test_4(); //maxHeap_test(); //test_5_1(); test_7(); return 0; }
Okay,第7题的完整解题过程就到这里了,希望大家多指教。
路漫漫其修远兮,吾将上下而…
相关文章推荐
- 数据结构和算法经典100题-第24题
- 数据结构和算法经典100题-第30题
- 数据结构和算法经典100题-第11题
- 数据结构和算法经典100题-第13题
- 数据结构和算法经典100题-第16题
- 数据结构和算法经典100题-第33题
- 数据结构和算法经典100题-第19题
- 数据结构和算法经典100题-第2题
- 数据结构和算法经典100题-第27题
- 数据结构和算法经典100题-第3题
- 数据结构和算法经典100题-第4题
- 数据结构和算法经典100题-第18题
- 数据结构和算法经典100题-第20题
- 数据结构和算法经典100题-第10题
- 数据结构和算法经典100题-第29题
- 数据结构和算法经典100题-第22题
- 数据结构和算法经典100题-第32题
- 数据结构和算法经典100题-第1题
- 数据结构和算法经典100题-第26题
- 数据结构和算法经典100题-第9题