博客
关于我
建立双头链表及判断两个链表共同后缀的起始位置
阅读量: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/

    你可能感兴趣的文章
    Node-RED中使用json节点解析JSON数据
    查看>>
    Node-RED中使用node-random节点来实现随机数在折线图中显示
    查看>>
    Node-RED中使用node-red-browser-utils节点实现选择Windows操作系统中的文件并实现图片预览
    查看>>
    Node-RED中使用node-red-contrib-image-output节点实现图片预览
    查看>>
    Node-RED中使用node-red-node-ui-iframe节点实现内嵌iframe访问其他网站的效果
    查看>>
    Node-RED中使用Notification元件显示警告讯息框(温度过高提示)
    查看>>
    Node-RED中使用range范围节点实现从一个范围对应至另一个范围
    查看>>
    Node-RED中实现HTML表单提交和获取提交的内容
    查看>>
    Vue3+elementplus实现图片上传下载(最强实践)
    查看>>
    Node-RED中将CSV数据写入txt文件并从文件中读取解析数据
    查看>>
    Node-RED中建立TCP服务端和客户端
    查看>>
    Node-RED中建立Websocket客户端连接
    查看>>
    Node-RED中建立静态网页和动态网页内容
    查看>>
    Vue3+Element-ul学生管理系统(第二十二课)
    查看>>
    Node-RED中怎样让网站返回JSON数据
    查看>>
    Node-RED中根据HTML文件建立Web网站
    查看>>
    Node-RED中解析高德地图天气api的json数据显示天气仪表盘
    查看>>
    Node-RED中连接Mysql数据库并实现增删改查的操作
    查看>>
    Node-RED中通过node-red-ui-webcam节点实现访问摄像头并截取照片预览
    查看>>
    Node-RED中配置周期性执行、指定时间阶段执行、指定时间执行事件
    查看>>