快慢指针的概念及其应用

一.概念

快慢指针中的快慢是指移动的步长,及每次向前移速度的快慢。例如:快指针每次沿链表向前移动2,慢指针每次向前移动1.

二.应用

  • 判断单链表是否有环
    假设链表存在环,此时定义两个指针,一个指针每次向前移动两个位置(快指针),另一个指针每次向前移动一步(慢指针),若快指针到达NULL,则说明链表以NULL结尾,没有环。如果快指针追上慢指针,则表示该链表有环。
    代码实现:
#include <iostream>
using namespace std;
//结点结构体
typedef struct Node
{
    char c;
    struct Node *next;
}Node, *LinkList;
//打印链表
void PutOut(LinkList H)
{
    LinkList p;
    p = H->next;
    while (p)
    {
        cout << p->c << "  ";
        p = p->next;
    }
    cout << endl;
}
//判断链表是否有环
bool HasLoop(Node *H)
{
    Node *slow = H;
    Node *fast = H;
    while (fast->next != NULL)
    {
        slow = slow->next;       //慢指针每次移动一步
        fast = fast->next->next; //快指针每次移动两步
        //相遇,有环
        if (slow == fast)
        {
            cout << "此链表有环!" << endl;
            return true;
        }
    }
    //快指针到达链表尾,没有相遇,无环
    if (fast->next == NULL)
    {
        cout << "此链表无环!" << endl;
        return false;
    }
}

int main(void)
{
    //创建一个无环链表用于进行验证
    LinkList H = new Node();
    Node d = { 'd', NULL };
    Node c = { 'c', &d };
    Node b = { 'b', &c };
    Node a = { 'a', &b };
    H->next = &a;
    PutOut(H);
    HasLoop(H);

    //创建一个有环链表用于验证
    LinkList New_H = new Node();
    Node A, B, C, D;
    A.c = 'A';
    B.c = 'B';
    C.c = 'C';
    D.c = 'D';
    New_H->next = &A;
    A.next = &B;
    B.next = &C;
    C.next = &D;
    D.next = &B;

    HasLoop(New_H);

    return 0;
}
  • 在有序链表中寻找中位数
    原理:由于快指针的移动速度是慢指针的2倍,所以当快指针到达链表尾时,慢指针正好到达链表中点。可以不借助计数器实现寻找中位数的功能。
  • 输出链表中的倒数第K个结点
    原理:定义两个指针,第一个指针从链表的头指针开始遍历向前走k-1步,第二个指针保持不动;从第k步开始,第二个指针也开始从头指针遍历,由于两个指针的距离保持在k-1,当第一个指针到达链表尾时,第二个指针正好指向链表的倒数第k个结点。
    代码实现:
#include <iostream>
#include <malloc.h>
using namespace std;
/*
若第一个指针先走 K 步,则两个指针同时移动时的循环条件是while(p != NULL)
若第一个指针先走 K-1 步,则两个指针同时移动时的循环条件是 while(p->next != NULL)
*/
typedef struct Node
{
    char c;
    struct Node *next;
}Node, *LinkList;

void PutOut(LinkList H)
{
    LinkList p;
    p = H->next;
    while (p)
    {
        cout << p->c << "  ";
        p = p->next;
    }
    cout << endl;
}

void Rec_K(LinkList L, int K)
{
    LinkList pre, late;
    pre = L;
    late = L;
    int i;

    for (i = 0; i < K-1; ++i)
    {
        pre = pre->next;
    }
    while (pre->next != NULL)
    {
        pre = pre->next;
        late = late->next;
    }
    cout << "倒数第" << K << "个结点的值为" << late->c << endl;
}
int main(void)
{
    LinkList H = new Node();
    Node d = { 'd', NULL };
    Node c = { 'c', &d };
    Node b = { 'b', &c };
    Node a = { 'a', &b };
    H->next = &a;
    PutOut(H);
    Rec_K(H, 2);

    return 0;
}
  • 判断两个单向链表是否相交,若相交,找出它们的第一个公共结点
    原理:分别遍历两个链表到末尾,若末尾结点相同,则说明它们相交,否则不相交。
    代码验证:
#include <iostream>
using namespace std;

typedef struct NODE
{
    int data;
    struct NODE *next;
}Node,*LinkList;
//链表初始化
LinkList InitList()
{
    LinkList H;
    H = (LinkList)malloc(sizeof(LinkList));
    H->next = NULL;
    return H;
}
//创建两条相交链表(V形或者Y形,不可能是X形,因为相交后,后续结点都一致)
//再创建一条与之都不相交的链表来进行验证
void CreatByTail_X(LinkList A, LinkList B, LinkList C)
{
    int i = 1, j = 1, k = 1;
    Node *pA, *pB, *pC, *tail_A, *tail_B, *tail_C;
    tail_A = A;
    tail_B = B;
    tail_C = C;

    //建立链表A
    while (i <= 5)
    {
        pA = (Node*)malloc(sizeof(Node));
        pA->data = i + 3;
        pA->next = tail_A->next;
        tail_A->next = pA;
        tail_A = tail_A->next;
        i++;
    }
    tail_A->next = NULL;

    //建立链表B
    while (j <=3 )
    {
        pB = (Node*)malloc(sizeof(Node));
        pB->data = j;
        tail_B->next = pB;
        tail_B = tail_B->next;
        j++;
    }
    //使pA从头结点开始后移,记录第四个结点位置,让tail_B指向它,则构成相交链表
    i = 0;
    pA = A;
    while (i < 4)
    {
        pA = pA->next;
        i++;
    }
    tail_B->next = pA;

    //建立链表C
    while (k <= 6)
    {
        pC = (Node*)malloc(sizeof(Node));
        pC->data = k;
        pC->next = tail_C->next;
        tail_C->next = pC;
        tail_C = tail_C->next;
        k++;
    }
    tail_C->next = NULL;
}
void PutOut(LinkList L)
{
    Node *p;
    p = L->next;
    while (p != NULL)
    {
        cout << p->data << " -> ";
        p = p->next;
    }
    cout << "\b\b\b\b    " << endl;
}
void Is_InterSert(LinkList _A, LinkList _B)
{
    Node *_pA, *_pB;
    _pA = _A;
    _pB = _B;
    while (_pA != NULL && _pB != NULL)
    {
        //使两条链表的指针同时向后移动,若在某一处指向相同,则链表相交
        _pA = _pA->next;
        _pB = _pB->next;
        if (_pA == _pB)
        {
            cout << "相交了!" << endl;
            break;
        }
    }
    if (_pA != _pB)
    {
        cout << "未相交!" << endl;
    }
}
int main(void)
{
    LinkList A;
    A = InitList();
    LinkList B;
    B = InitList();
    LinkList C;
    C = InitList();

    CreatByTail_X(A, B, C);

    cout << "链表A:" << endl;
    PutOut(A);
    cout << "链表B:" << endl;
    PutOut(B);
    cout << "链表C:" << endl;
    PutOut(C);

    cout << "A 与 B";
    Is_InterSert(A, B);
    cout << "A 与 C";
    Is_InterSert(A, C);
    cout << "B 与 C";
    Is_InterSert(B, C);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值