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

本文共 3696 字,大约阅读时间需要 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/

    你可能感兴趣的文章
    ngrok内网穿透可以实现资源共享吗?快解析更加简洁
    查看>>
    NHibernate学习[1]
    查看>>
    NHibernate异常:No persister for的解决办法
    查看>>
    NIFI1.21.0_java.net.SocketException:_Too many open files 打开的文件太多_实际操作---大数据之Nifi工作笔记0051
    查看>>
    NIFI1.21.0_Mysql到Mysql增量CDC同步中_日期类型_以及null数据同步处理补充---大数据之Nifi工作笔记0057
    查看>>
    NIFI1.21.0_Mysql到Mysql增量CDC同步中_补充_更新时如果目标表中不存在记录就改为插入数据_Postgresql_Hbase也适用---大数据之Nifi工作笔记0059
    查看>>
    NIFI1.21.0_NIFI和hadoop蹦了_200G集群磁盘又满了_Jps看不到进程了_Unable to write in /tmp. Aborting----大数据之Nifi工作笔记0052
    查看>>
    NIFI1.21.0最新版本安装_连接phoenix_单机版_Https登录_什么都没改换了最新版本的NIFI可以连接了_气人_实现插入数据到Hbase_实际操作---大数据之Nifi工作笔记0050
    查看>>
    NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_增删改数据分发及删除数据实时同步_通过分页解决变更记录过大问题_02----大数据之Nifi工作笔记0054
    查看>>
    NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_插入修改删除增量数据实时同步_通过分页解决变更记录过大问题_01----大数据之Nifi工作笔记0053
    查看>>
    NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表或全表增量同步_实现指定整库同步_或指定数据表同步配置_04---大数据之Nifi工作笔记0056
    查看>>
    NIFI1.23.2_最新版_性能优化通用_技巧积累_使用NIFI表达式过滤表_随时更新---大数据之Nifi工作笔记0063
    查看>>
    NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_根据binlog实现数据实时delete同步_实际操作04---大数据之Nifi工作笔记0043
    查看>>
    NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置binlog_使用处理器抓取binlog数据_实际操作01---大数据之Nifi工作笔记0040
    查看>>
    NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_实现数据插入数据到目标数据库_实际操作03---大数据之Nifi工作笔记0042
    查看>>
    NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_生成插入Sql语句_实际操作02---大数据之Nifi工作笔记0041
    查看>>
    NIFI从MySql中离线读取数据再导入到MySql中_03_来吧用NIFI实现_数据分页获取功能---大数据之Nifi工作笔记0038
    查看>>
    NIFI从MySql中离线读取数据再导入到MySql中_不带分页处理_01_QueryDatabaseTable获取数据_原0036---大数据之Nifi工作笔记0064
    查看>>
    NIFI从MySql中离线读取数据再导入到MySql中_无分页功能_02_转换数据_分割数据_提取JSON数据_替换拼接SQL_添加分页---大数据之Nifi工作笔记0037
    查看>>
    NIFI从PostGresql中离线读取数据再导入到MySql中_带有数据分页获取功能_不带分页不能用_NIFI资料太少了---大数据之Nifi工作笔记0039
    查看>>