如何解决使用单个链接列表筛选Eratosthenes C ++
嗨,我在使用C ++时遇到Eratosthenes筛问题。我必须使用单个链表进行此操作。我的程序正在运行,并且显示列表的第一个声明,但是我不知道如何正确删除非素数。我的功能对我不起作用。我应该如何更改删除功能?
#include <iostream>
#include <cmath>
using namespace std;
struct List
{
int number;
List* next;
};
List* head = new List;
void l_add(int n)
{
List* temp = head;
for (int i = 2; i <= n; i++)
{
temp->next = new List();
temp->number = i;
temp = temp->next;
}
}
void l_print()
{
List* temp = head;
while (temp->next != 0)
{
cout << temp->number << " ";
temp = temp->next;
}
cout << endl;
}
void l_delete(int n)
{
List* temp = head;
for (int i = 2; i < sqrt(n); i++)
{
if (temp->number % i == 0)
{
head = temp->next;
delete temp;
temp = head;
}
while (temp->next != 0)
{
if (temp->next->number % i == 0)
{
temp->next = temp->next->next;
delete temp->next;
}
temp = temp->next;
}
}
}
int main()
{
int n;
cout << "Enter up to which number to find prime numbers using Sieve of Eratosthenes: " << endl;
cin >> n;
l_add(n);
l_print();
l_delete(n);
l_print();
return 0;
}
解决方法
这将是l_delete方法的有效版本:
void l_delete(int n)
{
List* temp = head;
for (int i = 2; i < sqrt(n); i++)
{
while (temp->next != 0)
{
if (temp->next->number % i == 0 && temp->next->number != i)
{
List* temp2 = temp->next->next;
delete temp->next;
temp->next = temp2;
}
if(temp->next == 0) break;
temp = temp->next;
}
temp = head;
if (temp->number % i == 0 && temp->number != i)
{
head = temp->next;
delete temp;
temp = head;
}
}
}
您的删除方法存在一些问题。 算法逻辑问题:应该首先检查算法头,因为如果删除了算法头,则不检查新头的素性,您需要立即检查下一个新头,即旧-> next-> next。另外,您也没有检查数字是否等于分频器,在这种情况下,不应删除该数字。
编程逻辑问题: 在while循环中删除下一个节点时,与删除head相同,您需要另一个临时变量来存储temp-> next-> next,然后在删除后将其分配给temp-> next。
但是这里最大的问题是,这根本不是Eratosthenes筛子,你是 只需检查所有数字是否与小于sqrt(n)的所有其他数相除即可。它 相较于Eratosthenes筛子,它是次优的。如果您使用Google Eratosthenes筛子,则会发现很多详细的教程和说明。
,我喜欢Bran的宣传,我将添加一些技巧。
评论:全局变量很烂。当项目变大时,它们使事情难以追踪。我将head
移至main
并将其作为参数传递。我也放弃了哨兵节点,因为我发现它们在大多数情况下都比它们值得的麻烦更多。
int main()
{
int n;
cout << "Enter up to which number to find prime numbers using Sieve of Eratosthenes: " << endl;
if (cin >> n)
{
// should be a bit more logic here to automatically handle ns of 1 or 2
List* head = nullptr; // not using a sentinel node
l_add(head,n); // passing in head rather than global variable free-for-all
l_delete(head);
l_print(head);
return 0;
}
else
{
cout << "invalid input." << endl;
return 1;
}
}
当添加到链接列表时,除2外,您不需要任何偶数。因此,请勿添加它们。花费在迭代列表上的时间更少。之后,要确保节点按正确的顺序排列。
void l_add(List*& head,// passing in head. Easier to track
int n)
{
List** temp = &head; // head is a next pointer with a different name
// hiding it behind another pointer allows us to treat
// it like a next
// temp is now a pointer to next pointers. We can add directly to the
// last nodes's next pointer and also use it to access the current
// pointer if we need to
(*temp) = new List {2,nullptr}; // 2 is only even prime
temp = &(*temp)->next;
for (int i = 3; i <= n; i+=2) // start at 3 and only add odd numbers
{
(*temp) = new List {i,nullptr};
temp = &(*temp)->next; // Advance to next node
}
}
当我们遍历列表以消除倍数时,我们需要两个循环。一个要跟踪的节点是我们要消除的倍数,另一个要进行搜寻和消除的循环。请注意,我再次使用了指针到指针的技巧。这个技巧消除了遍历和删除节点所需的大约一半代码。
void l_delete(List * head)
{
List* last = head->next; // track the last known prime node. skip node 2.
// note this will blow up if there is no node 2.
while (last) // for every node still in the list
{
List** current = &last->next; // similar to trick above.
// if we have a pointer to the next to be
// updated,we don't need to track the previous node
while ((*current)) // look at every node after the last prime
{
if ((*current)->number % last->number == 0) // if it's a multiple,remove it.
{
List * to_del = (*current); //save node to delete
(*current) = (*current)->next; // link previous node to next node.
// effectively automatically advances the node
delete to_del;
}
else // proceed to next node
{
current = &(*current)->next;
}
}
last = last->next; // advance to next prime number
}
}
可能有足够的空间进行优化,但我的目标是提高可读性,因为如果我丢掉10行神秘的胡言乱语,没人会学到什么。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。