用哈希表判斷兩個單鏈表是否相交的問題

判斷兩個單鏈表是否相交,一般有下面幾種方法:
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;
    }       
}

這裏我沒有構造一個新的鏈表來測試,只是把構造第一個鏈表時創建的節點地址都記錄起來,用來驗證查找是否有效。

運行結果:
這裏寫圖片描述

發佈了46 篇原創文章 · 獲贊 22 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章