用哈希表判断两个单链表是否相交的问题

判断两个单链表是否相交,一般有下面几种方法:
1.遍历第一个链表,记录每次获得的节点地址,然后遍历第二个链表,看记录的节点地址是否存在第二个链表中,这种方法的时间复杂度为O(n^2)。

2.对第一个链表的每个节点地址构造哈希表,然后遍历第二个链表,查找当前节点是否存在哈希表中,此方式的时间复杂度为O(len1+len2)。

3.将其中一个链表首尾相接,遍历另一个链表,如果能达到首尾相接链表的头,说明两个链表存在公共部分,时间复杂度为O(len1+len2)。

下面给出第2种方法,用哈希表查找的实现代码。

首先定义链表数据结构:

typedef struct sigList{
    int data;
    struct sigList* nextNode;
}sigList_t;

接着构建单链表,这里我把事先定义好的组数存储的元素作为节点数据:

int data[] = {100,53,21,426,0,1235,19,83,26};
    sigList_t* Head = NULL;
    sigList_t* p;
    sigList_t* q;

    sigList_t* needToFind[9] = {NULL};  

    for(int idx = 0; idx < 9; idx++){
        p = (sigList_t*)malloc(sizeof(sigList_t));
        p->data = data[idx];
        //cout << "main:data is " << p->data << "," << "address is " << p << endl;
        p->nextNode = NULL;
        needToFind[idx] = p;
        if(Head == NULL){
            Head = p;
        }
        else{
            q->nextNode = p;
        }
        q = p;
    }

链表构造好后,思考:我们要把什么存入哈希表才能达到查找的目的?
两个链表相交是指从某个节点开始,存储的下一个节点的地址相同,如下图所示:
这里写图片描述
因此我们需要对节点地址构造哈希表,用一个数组存储这些节点地址:

sigList_t* storeRcd[9] = {NULL};

采用除留取余法构造哈希函数,记录长度为9,选一个小于或等于9的最大质数作取余数用,这里用7:

int Hash(void* key){//key传入的节点地址
    int Ckey = (int)key;
    return Ckey % 7;//除留取余法
}

接着开始构造哈希表,这里采用链地址法解决冲突,哈希表冲突指对key1 != key2,存在f(key1)=f(key2),链地址法就是把key1和key2作为节点放在同一个单链表中,这种表称为同义词子表,在哈希表中只存储同义词子表的头指针,如下图:
这里写图片描述

void InsertHash(sigList_t* L){
    sigList_t* tmp = L;
    sigList_t* p;
    sigList_t* tail[9] = {NULL};

    while(tmp != NULL){
        int addr = Hash(tmp);
        p = (sigList_t*)malloc(sizeof(sigList_t));//创建节点addr
        p->data = (int)tmp;//把地址转换成整型存储
        p->nextNode = NULL;
        //cout << "InsertHash data is " << tmp  << endl;
        if(storeRcd[addr] == NULL){//addr这个位置还没有key存储
            storeRcd[addr] = p; 
        }
        else{//addr位置已经存在key了,那就把当前要存储的key放在最后一个数据后面
            tail[addr]->nextNode = p;
        }
        tail[addr] = p;
        tmp = tmp->nextNode;
    }
}

最后实现利用哈希表进行查找:

bool SearchHash(void* key){
    int Ckey = (int)key;
    int addr = Hash(key);
    sigList_t* tmp = storeRcd[addr];
    while(tmp != NULL){//遍历addr存储的单链表,直到查找到节点或者不存在
        //cout << "SearchHash tmp is " << hex << tmp->data << endl;
        if(tmp->data == Ckey)//匹配
            return true;
        tmp = tmp->nextNode;
    }
    return false;
}

完整代码:

#include <string.h>
#include <malloc.h>
#include <iostream>

using namespace std;

typedef struct sigList{
    int data;
    struct sigList* nextNode;
}sigList_t;

sigList_t* storeRcd[9] = {NULL};

void PrintData(sigList_t* L){
    sigList_t* tmp = L;
    while(tmp != NULL){
        cout << hex << tmp->data << " ";
        tmp = tmp->nextNode;    
    }
    cout << endl;
}

int Hash(void* key){
    int Ckey = (int)key;
    //cout << "Hash:" << Ckey % 7 << endl; 
    return Ckey % 7;
}

void InsertHash(sigList_t* L){
    sigList_t* tmp = L;
    sigList_t* p;
    sigList_t* tail[9] = {NULL};

    while(tmp != NULL){
        int addr = Hash(tmp);
        p = (sigList_t*)malloc(sizeof(sigList_t));
        p->data = (int)tmp;
        p->nextNode = NULL;
        //cout << "InsertHash data is " << tmp  << endl;
        if(storeRcd[addr] == NULL){
            storeRcd[addr] = p; 
        }
        else{
            tail[addr]->nextNode = p;
        }
        tail[addr] = p;
        tmp = tmp->nextNode;
    }
}

bool SearchHash(void* key){
    int Ckey = (int)key;
    int addr = Hash(key);
    sigList_t* tmp = storeRcd[addr];
    while(tmp != NULL){
        //cout << "SearchHash tmp is " << hex << tmp->data << endl;
        if(tmp->data == Ckey)
            return true;
        tmp = tmp->nextNode;
    }
    return false;
}

int main(){
    int data[] = {100,53,21,426,0,1235,19,83,26};
    sigList_t* Head = NULL;
    sigList_t* p;
    sigList_t* q;

    sigList_t* needToFind[9] = {NULL};  //把每个节点的记录存储起来,测试查找使用

    for(int idx = 0; idx < 9; idx++){
        p = (sigList_t*)malloc(sizeof(sigList_t));
        p->data = data[idx];
        //cout << "main:data is " << p->data << "," << "address is " << p << endl;
        p->nextNode = NULL;
        needToFind[idx] = p;
        if(Head == NULL){
            Head = p;
        }
        else{
            q->nextNode = p;
        }
        q = p;
    }

    InsertHash(Head);

    for(int idx = 0; idx < 9; idx++){
        cout << idx << ":";
        PrintData(storeRcd[idx]);
    }

    cout << "search record: " << needToFind[7] << ",";
    if(SearchHash(needToFind[7])){
        cout << "the record is exist in the List" << endl;
    }
    else{
        cout << "the record is not exist in the List" << endl;
    }

    cout << "search record: " << needToFind[7]+1 << ",";
    if(SearchHash(needToFind[7]+1)){
        cout << "the record is exist in the List" << endl;
    }
    else{
        cout << "the record is not exist in the List" << endl;
    }       
}

这里我没有构造一个新的链表来测试,只是把构造第一个链表时创建的节点地址都记录起来,用来验证查找是否有效。

运行结果:
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值