Давайте на мгновение оставим код в стороне и представим, что вы могли бы сделать это с помощью ручки и бумаги: вы должны были бы записать числа 2 3 4 ... 2n и начать с «2» (внешний l oop). Затем вы должны (внутренний l oop) отмечать (обратите внимание: НЕ стирать, а только отмечать!) Каждое второе число, начинающееся с 2 * 2 = 4. Затем вы должны вернуться к внешнему l oop, считать «3» и пометить каждое третье число, начинающееся с 3 * 2 = 6 (на самом деле, также можно начинать с 3 ^ 2 = 9).
Это маркировка переводится в установку элементов в массиве на 0, и в качестве последнего шага вы будете рассматривать только немаркированные (т.е. не 0) элементы.
В вашем подходе теперь вы хотите удалить узлы из связанного списка . Перевести это на язык ручки и бумаги - значит стереть числа с бумаги. Затем вы снова начинаете с «2», стираете кратные 2, затем go до «3» и стираете кратные 3. Важное изменение заключается в том, что вы больше не можете просто слепо стирать каждое третье число, но вы бы на самом деле нужно смотреть на числа и спрашивать себя: это кратное 3?
Конечно, вы могли бы это сделать, и вы также можете запрограммировать это, но это уже не будет решето для эратосфена. Сила алгоритма заключается в том, что любые кратные числа легко обнаруживаются по их индексу:
В предоставленном вами коде simp[i] == 0 || simp[i] == i
сохраняется все время, т.е. число либо помечено, либо его индекс на самом деле является значением сам. Следовательно, вам не нужно смотреть на число и проверять, можно ли его разделить, вы можете просто сделать суждение на основе его индекса.