博客
关于我
建立双头链表及判断两个链表共同后缀的起始位置
阅读量:785 次
发布时间:2019-03-24

本文共 3804 字,大约阅读时间需要 12 分钟。

双头链表(OrIGHL Link List)是一种节省存储空间的数据结构,当两个字符串结尾有相同的部分,双头链表允许这些相同的结点共享存储空间。以下是实现双头链表和查找公共后缀起始位置的算法详细说明。

1. 建立双头链表

算法目标:根据两个字符串分别构建双头链表,在两个字符串末尾有相同字符的部分,允许它们共享结点存储空间。

实现步骤

  • 初始化两个链表头结点:创建两个链表对象 list1list2,它们各自的头结点初始化为空。
  • 构建二者共同的后缀部分
    • 从字符串末尾开始向前遍历,比较 str1str2 的对应字符。
    • 当发现字符相同时,创建新节点将其插入链表,共享存储空间。
    • 停止异常字符比较时(字符不同)。
  • 处理剩余部分
    • str1 剩余字符依次插入 list1
    • str2 剩余字符依次插入 list2
  • 设置头结点:为每个链表添加头结点,将其设置为链表起点。
  • 示例代码

    // 初始化链表节点
    struct LNode {
    char data;
    LNode* next;
    };
    // 创建链表头结点辅助函数
    void initLinkList(LNode*& list) {
    list = new LNode;
    list->next = nullptr;
    }
    // 构建双头链表,共享相同的后缀存储空间
    void buildDoubleLinkedList(char* str1, char* str2, int m, int n,
    LNode*& list1, LNode*& list2) {
    list1 = list2 = nullptr; // 初始化双链表头指针为空
    // 从字符串末尾开始,向前构建链表
    int i = m - 1, j = n - 1;
    LNode* current;
    while (i >= 0 && j >= 0 && str1[i] == str2[j]) {
    current = new LNode;
    current->data = str1[i];
    current->next = list1; // 将当前结点连接到已有链表
    list1 = current;
    --i, --j;
    current = nullptr; // 循环后,current指针重置为null
    }
    // 共享当前链表的结尾节点
    list2 = list1;
    // 处理剩余部分,将其插入链表中
    // 处理str1的剩余部分
    while (i >= 0) {
    current = new LNode;
    current->data = str1[i];
    current->next = list1;
    list1 = current;
    --i;
    }
    // 处理str2的剩余部分
    while (j >= 0) {
    current = new LNode;
    current->data = str2[j];
    current->next = list2;
    list2 = current;
    --j;
    }
    // 添加头结点
    list1 = new LNode;
    list1->next = list1;
    list2 = new LNode;
    list2->next = list2;
    }

    2. 查找双头链表的公共后缀起始位置

    算法目标:找到两个双头链表的共同后缀起始节点位置,返回该节点的指针。

    实现步骤

  • 计算链表长度:获取两个链表的长度。
  • 确定遍历顺序:较长链表先进行长度差量的移动,确保两个指针同时到达最后一个节点。
  • 同步遍历:同时遍历长链表和短链表,并比较对应节点,直到找到相同的节点。
  • 返回起始节点:找到第一个公共节点即为共同后缀的起始点。
  • 示例代码

    // 计算链表长度
    int getLength(LNode* head) {
    int len = 0;
    LNode* current = head->next; // 除去头结点
    while (current) {
    len++;
    current = current->next;
    }
    return len;
    }
    // 查找双头链表的公共后缀起始位置
    LNode* findCommonSuffixStart(LNode* listA, LNode* listB) {
    int lenA = getLength(listA);
    int lenB = getLength(listB);
    LNode* longList; // 长度较长的链表指针
    LNode* shortList; // 较短的链表指针
    int len = (lenA > lenB) ? (lenA - lenB) : (lenB - lenA);
    // 调整指针使两个链表尾部对齐
    if (lenA > lenB) {
    longList = listA->next; // Skip 'lenB' 个节点后到达较长链表尾部
    shortList = listB->next; // 长度不变
    len = lenB;
    } else {
    longList = listB->next;
    shortList = listA->next;
    len = lenA;
    }
    // 同时移动两个链表的尾部指针
    while (len-- >= 0 && longList && shortList) {
    longList = longList->next;
    if (longList && shortList && longList == shortList) {
    return longList; // 返回首个公共节点
    }
    shortList = shortList->next;
    }
    return nullptr; // 无公共后缀时返回空
    }

    3. 测试示例

    // 测试构建链表和查找公共后缀
    int main() {
    string str1 = "abcdxyz", str2 = "abcdefghijk";
    // 初始化链表存储空间
    LNode* list1 = new LNode, *list2 = new LNode; // 头结点(双头链表)
    // 构建双头链表
    int m = str1.size(), n = str2.size();
    char* s1 = new char[m], s2 = new char[n];
    memcpy(s1, str1.c_str(), m);
    memcpy(s2, str2.c_str(), n);
    buildDoubleLinkedList(s1, s2, m, n, list1, list2);
    // 打印双头链表内容
    cout << "list1: ";
    printList(list1);
    cout << "list2: ";
    printList(list2);
    // 查找公共后缀开始的结点
    LNode* commonNode = findCommonSuffixStart(list1->next, list2->next);
    if (commonNode) {
    cout << "第一个公共后缀的起始节点: " << commonNode->data << endl;
    } else {
    cout << "没有公共后缀" << endl;
    }
    return 0;
    }

    4. 功能说明

    • buildDoubleLinkedList:根据给定字符串构建双带链表,在尾部存在相同字符的条目会共享存储。
    • findCommonSuffixStart:返回两个双档链表的第一个共同节点,即后缀的开始位置。
    • getLength:计算链表的长度。
    • printList:输出链表内容,并用空格分隔每个节点的数据。

    注意事项

    • 确保在动态内存分配时避免指针泄漏。
    • 为每个链表分配足够的内存空间。
    • 适用于字符串互相后缀可能为空的情况。

    转载地址:http://rehkk.baihongyu.com/

    你可能感兴趣的文章
    Node.js初体验
    查看>>
    Node.js升级工具n
    查看>>
    Node.js卸载超详细步骤(附图文讲解)
    查看>>
    Node.js卸载超详细步骤(附图文讲解)
    查看>>
    Node.js基于Express框架搭建一个简单的注册登录Web功能
    查看>>
    node.js学习之npm 入门 —8.《怎样创建,发布,升级你的npm,node模块》
    查看>>
    Node.js安装与配置指南:轻松启航您的JavaScript服务器之旅
    查看>>
    Node.js安装及环境配置之Windows篇
    查看>>
    Node.js安装和入门 - 2行代码让你能够启动一个Server
    查看>>
    node.js安装方法
    查看>>
    Node.js官网无法正常访问时安装NodeJS的方法
    查看>>
    node.js模块、包
    查看>>
    node.js的express框架用法(一)
    查看>>
    Node.js的交互式解释器(REPL)
    查看>>
    Node.js的循环与异步问题
    查看>>
    Node.js高级编程:用Javascript构建可伸缩应用(1)1.1 介绍和安装-安装Node
    查看>>
    nodejs + socket.io 同时使用http 和 https
    查看>>
    NodeJS @kubernetes/client-node连接到kubernetes集群的方法
    查看>>
    NodeJS API简介
    查看>>
    Nodejs express 获取url参数,post参数的三种方式
    查看>>