C++ 创建哈希链接方法时无法访问头指针

C++ 创建哈希链接方法时无法访问头指针,c++,class,pointers,hash,linked-list,C++,Class,Pointers,Hash,Linked List,我正在创建一个使用链表链接的方法,在这里我声明了3个类,即node,LL(链表),chaining,我无法处理 在chaining类中,我动态地创建一个指向链表的指针数组,并使用LL类将链表的头指针设置为null,但程序无法访问它,因此出现了分段错误。通过调试,我发现了故障线路,如下所示: coutindex=i; t->next=NULL; 水头=t; t=零; } 否则{ 节点*p=头部; 节点*r; while(p | | datadata){ r=p; p=p->next; } node

我正在创建一个使用链表链接的方法,在这里我声明了3个类,即node,LL(链表),chaining,我无法处理 在chaining类中,我动态地创建一个指向链表的指针数组,并使用LL类将链表的头指针设置为null,但程序无法访问它,因此出现了分段错误。通过调试,我发现了故障线路,如下所示:

coutindex=i;
t->next=NULL;
水头=t;
t=零;
}
否则{
节点*p=头部;
节点*r;
while(p | | datadata){
r=p;
p=p->next;
}
node*t=新节点;
t->data=数据;
t->index=i;
t->next=NULL;
r->next=t;
t=零;
r=NULL;
}
}
};
类链接{
公众:
LL**arr;
int n;
链接(向量和nums){
n=nums.size();
arr=新LL*[n];
for(int i=0;iInsertForChaining(nums[i],i);
}
}
整数搜索(整数键){
节点*p=arr[键%n]->头;
while(p){
如果(p->data==键){
返回p->index;
}
p=p->next;
}
返回-1;
}
};
内部主(空){
向量v1={1,2,3,4,5,6,7,8,9};
您可能有两个错误:

第47行中,您可以动态创建链接列表类。另请参见文章作为参考

arr=new LL*[n];//数据){//无法检查null p->data
当您到达列表末尾时,这也会导致分段错误

使用第一个建议的解决方案并删除while语句中的第二个检查,程序的输出现在是:

hello start
00x8230900x8230900x8230900x8230900x8230900x8230900x8230900x823090hello

Process finished with exit code 0
您有两个bug:

第47行中,您可以动态创建链接列表类。另请参见文章作为参考

arr=new LL*[n];//数据){//无法检查null p->data
当您到达列表末尾时,这也会导致分段错误

使用第一个建议的解决方案并删除while语句中的第二个检查,程序的输出现在是:

hello start
00x8230900x8230900x8230900x8230900x8230900x8230900x8230900x823090hello

Process finished with exit code 0

实际上,您正在尝试使用
arr
作为哈希表对哈希表的开头进行编码,然后使用前向链接来处理任何冲突。在您的情况下,由于使用
nums[i]的哈希值具有
n
唯一值%n
n
存储桶,将不会发生任何冲突,因此在每个
arr[i]
位置都有一个单节点列表

首先,由于
类LL
包含
节点*head
成员,您不需要声明和分配指针,然后使用
LL**arr;
分配节点,只需为
LL*arr;
分配每个bucket的
类LL
的一个实例作为哈希表。然后
插入链接()
将在每次链接任何现有节点时分配并插入一个新的
节点。您可以按以下方式执行此操作:

    Chaining (std::vector<int>&nums) {
        n = nums.size();
        arr = new LL[n];
        for (int i = 0; i < n; i++) {
            int storage = nums[i] % n;
            arr[storage].InsertForChaining (nums[i], i);
        }
    }
当您编写一个使用
new
进行分配的类时,请确保您编写了一个析构函数来
delete
您已分配的内存,否则您将泄漏内存。只需要一个简单的析构函数,例如

    ~Chaining() {
        for (int i = 0; i < n; i++) {
            while (arr[i].head) {
                node *victim = arr[i].head;
                arr[i].head = arr[i].head->next;
                delete victim;
            }
        }
        delete[] arr;
        arr = nullptr;
    }
您可以添加一个短函数来输出哈希表的内容以确认存储的值。只需在每个bucket上循环并从
arr[i].head
迭代,直到达到
nullptr
。这可以通过以下方法完成:

    void prnlist () {
        std::cout.put ('\n');
        
        for (int i = 0; i < n; i++) {
            node *t = arr[i].head;
            std::cout << "arr[" << i << "]:";
            while (t) {
                std::cout << " (" << t->data << ", " << t->index << ")";
                t = t->next;
            }
            std::cout.put ('\n');
        }
    }
你会想要阅读和阅读。早养成好习惯比晚养成坏习惯容易

另一个小缺点是不需要输出字符串文字,然后再输出
endl
,例如

    cout<<"hello start"<<endl;
总而言之,你可以做到:

#include <iostream>
#include <vector>

class node {
    public:
    int data;
    int index;
    node *next;
};

class LL {
    public:
    node *head = nullptr;
    void InsertForChaining (int data,int i) {
        node *t = new node;
        t->data = data;
        t->index = i;
        t->next = head;
        head = t;
    }
};

class Chaining {
    public:
    LL *arr;
    int n;
    Chaining (std::vector<int>&nums) {
        n = nums.size();
        arr = new LL[n];
        for (int i = 0; i < n; i++) {
            int storage = nums[i] % n;
            arr[storage].InsertForChaining (nums[i], i);
        }
    }
    ~Chaining() {
        for (int i = 0; i < n; i++) {
            while (arr[i].head) {
                node *victim = arr[i].head;
                arr[i].head = arr[i].head->next;
                delete victim;
            }
        }
        delete[] arr;
        arr = nullptr;
    }
    void prnlist () {
        std::cout.put ('\n');
        
        for (int i = 0; i < n; i++) {
            node *t = arr[i].head;
            std::cout << "arr[" << i << "]:";
            while (t) {
                std::cout << " (" << t->data << ", " << t->index << ")";
                t = t->next;
            }
            std::cout.put ('\n');
        }
    }
    int search (int key) {
        node *p = arr[key%n].head;
        
        while (p && p->data != key)
            p = p->next;
        
        return p ? p->index : -1;
    }
};

int main(void) {
    
    std::vector<int>v1 = {1,2,3,4,5,6,7,8,9};
    std::cout << "hello start\n";
    
    Chaining c1(v1);
    c1.prnlist();
    
    std::cout << "\nvalidating search of each value.\n";
    for (const auto i : v1)
        if (c1.search(i) == -1)
            std::cerr << "error: " << i << " not found in table.\n";
    std::cout << "(validation done)\n";
    
    std::cout << "\nhello\n";
}
内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于所分配的任何内存块,您有两个责任:(1)始终保留指向内存块起始地址的指针,以便(2)在不再需要它时可以释放它

必须使用内存错误检查程序,以确保您不会试图访问内存或写入超出/超出分配的块的边界,尝试在未初始化的值上读取或基于条件跳转,最后确认释放所有已分配的内存

对于Linux
valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很容易使用,只需运行程序即可

$valgrind./bin/chaining\u向量
==15924==Memcheck,内存错误检测器
==15924==2002-2017年版权(C)和GNU GPL'd,朱利安·苏厄德等人。
==15924==使用Valgrind-3.13.0和LibVEX;使用-h重新运行以获取版权信息
==15924==命令:./bin/chaining\u向量
==15924==
你好,开始
arr[0]:(9,8)
arr[1]:(1,0)
arr[2]:(2,1)
arr[3]:(3,2)
arr[4]:(4,3)
arr[5]:(5,4)
arr[6]:(6,5)
arr[7]:(7,6)
arr[8]:(8,7)
正在验证对每个值的搜索。
(已完成验证)
你好
==15924==
==15924==堆摘要:
==15924==在出口处使用:0个块中有0个字节
==15924==总堆使用率:13个alloc,13个free,分配了73980字节
==15924==
==15924==所有堆块都已释放--不可能存在泄漏
==15924==
==15924==对于检测到的和抑制的错误计数,请使用:-v重新运行
==15924==错误摘要:来自0个上下文的0个错误(已抑制:来自0的0)
始终确认已释放所有已分配的内存,并且没有内存错误


仔细检查一下,如果您还有其他问题,请告诉我。

您实际上是在尝试使用
arr
作为哈希表,然后使用Forward chain i对哈希表的开头进行编码
int main(void) {
    
    std::vector<int>v1 = {1,2,3,4,5,6,7,8,9};
    std::cout << "hello start\n";
    
    Chaining c1(v1);
    c1.prnlist();
    
    std::cout << "\nvalidating search of each value.\n";
    for (const auto i : v1)
        if (c1.search(i) == -1)
            std::cerr << "error: " << i << " not found in table.\n";
    std::cout << "(validation done)\n";
    
    std::cout << "\nhello\n";
}
    cout<<"hello start"<<endl;
    std::cout << "hello start\n";
#include <iostream>
#include <vector>

class node {
    public:
    int data;
    int index;
    node *next;
};

class LL {
    public:
    node *head = nullptr;
    void InsertForChaining (int data,int i) {
        node *t = new node;
        t->data = data;
        t->index = i;
        t->next = head;
        head = t;
    }
};

class Chaining {
    public:
    LL *arr;
    int n;
    Chaining (std::vector<int>&nums) {
        n = nums.size();
        arr = new LL[n];
        for (int i = 0; i < n; i++) {
            int storage = nums[i] % n;
            arr[storage].InsertForChaining (nums[i], i);
        }
    }
    ~Chaining() {
        for (int i = 0; i < n; i++) {
            while (arr[i].head) {
                node *victim = arr[i].head;
                arr[i].head = arr[i].head->next;
                delete victim;
            }
        }
        delete[] arr;
        arr = nullptr;
    }
    void prnlist () {
        std::cout.put ('\n');
        
        for (int i = 0; i < n; i++) {
            node *t = arr[i].head;
            std::cout << "arr[" << i << "]:";
            while (t) {
                std::cout << " (" << t->data << ", " << t->index << ")";
                t = t->next;
            }
            std::cout.put ('\n');
        }
    }
    int search (int key) {
        node *p = arr[key%n].head;
        
        while (p && p->data != key)
            p = p->next;
        
        return p ? p->index : -1;
    }
};

int main(void) {
    
    std::vector<int>v1 = {1,2,3,4,5,6,7,8,9};
    std::cout << "hello start\n";
    
    Chaining c1(v1);
    c1.prnlist();
    
    std::cout << "\nvalidating search of each value.\n";
    for (const auto i : v1)
        if (c1.search(i) == -1)
            std::cerr << "error: " << i << " not found in table.\n";
    std::cout << "(validation done)\n";
    
    std::cout << "\nhello\n";
}