ورود

View Full Version : توضیح درباره کدهای زیر



Hossein8867
دوشنبه 28 اردیبهشت 1394, 11:29 صبح
سلام دوستان عزیز.کدهای زیر در مورد اعداد اول یک تا صد است.لطفا بفرمایید برنامه چگونه کار می کند؟چرا ...,2,3,5 چاپ می شوند ولی ...,4,6,8 چاپ نمی شوند؟

public class PrimeNumbers {


public static void myMethod() {
int i = 0, j = 0;
for (i = 2; i <= 100; i++) {
for (j = 2; j <= i; j++) {
if (i == j) {
System.out.print(i + "\t");

} else if (i % j == 0) {
break;




}
}
}








}




public static void main(String[] args) {
myMethod();
}








}

محمد فدوی
سه شنبه 29 اردیبهشت 1394, 23:00 عصر
سلام.
برای چک کردن این‌که آیا n یه عدد اول هست یا نه یکی از روش‌ها که خیلی هم بهینه نیست اینه که بیایم ببینیم آیا n به حداقل یکی از اعداد بازه‌ی «۲ تا جزءصحیح جذر n» بخش پذیر هست یا نه، اگر به حداقل یکیشون بخش‌پذیر بود یعنی مرکبه و در غیراینصورت اوله. منتهاش برنامه‌ی شما به جای اینکه تا جذر n رو تست کنه اومده تا خود n رو تست کرده (که یه کار بیهوده‌ست) و این تست رو برای همه‌ی اعداد ۲ تا ۱۰۰ انجام می‌ده...
تکنیکای استخراج اعداد اول خیلی متفاوتن و وابسته به نیاز ما هم تکنیک‌های مختلفی وجود داره. اما کد برنامه‌ی شما شاید اینجوری خوانا‌تر بشه:
public class PrimeNumbers {
public static boolean isPrime(int n) {
for(int i = 2; i * i <= n; i++) {
if(n % i == 0) {
return false;
}
}
return true;
}

public static void main(String[] args) {
for(int i = 2; i <= 100; i++) {
if(isPrime(i)) {
System.out.print(i + "\t");
}
}
}
}

موفق باشید.

Hossein8867
چهارشنبه 30 اردیبهشت 1394, 11:26 صبح
با سلام خدمت شما جناب فدوی عزیز از پاسخگویی شما بسیار ممنونم.در کدهایی که من در بالا نوشتم i اول برابر با 2 است و j نیز برابر با 2 است وقتی شرط داخل if صحیح باشد i چاپ می شود و در غیر اینصورت شرط بعد از else if اجرا می شود.سوال من اینجاست در این کد وقتی به j یکی اضافه می شود به i هم یکی اضافه می شود 2 برابر 2 است ولی باقیمانده تقسیمش هم صفر می شود یا 4 برابر 4 است اما چاپ نمی شود.البته می دانم این کد زیاد بهینه نیست ولی می خواهم طرز عملکردش را بدانم.با تشکر

محمد فدوی
چهارشنبه 30 اردیبهشت 1394, 17:04 عصر
مقدار i و j همیشه یکی نیست. اولین بار که حلقه‌ی خارجی‌تر اجرا می‌شه، داریم: i = 2 و بعد که وارد حلقه‌ی داخلی می‌شیم مقدار j = 2 و چون i == j پس ۲ یه عدد اوله و درست هم هست.
اما در ادامه وقتی حلقه‌ی خارجی دوباره اجرا بشه i = 3 میشه. اما توی حلقه‌ی داخلی j دوباره از ۲ شروع می‌کنه. پس هر بار که شمارنده‌ی حلقه‌ی خارجی (i) یه‌دونه زیاد می‌شه، شمارنده‌ی حلقه‌ی داخلی دوباره از اول، از ۲ شروع می‌کنه.
خب، حالا که اینو فهمیدیم بیایم جایی رو بررسی کنیم که حلقه‌ی خارجی‌تر به عدد ۳۵ رسیده و درحقیقت i = 35. خب، حلقه‌ی داخلی دوباره از ۲ شروع می‌کنه و یعنی j = 2. حالا این روند به ازای همه‌ی مقادیر j طی می‌شه:

۱. (j = 2, i = 35): آیا i == j؟ خیر - آیا i بر j بخشپذیر است؟ خیر، پس ادامه می‌دیم...
۲. (j = 3, i = 35): آیا i == j؟ خیر - آیا i بر j بخشپذیر است؟ خیر، پس ادامه می‌دیم...
۳. (j = 4, i = 35): آیا i == j؟ خیر - آیا i بر j بخشپذیر است؟ خیر، پس ادامه می‌دیم...
۴. (j = 5, i = 35): آیا i == j؟ خیر - آیا i بر j بخشپذیر است؟ بله، پس i یک عدد اول نیست و از حلقه‌ی داخلی خارج می‌شیم...
۵. (j = 2, i = 36): ...

همینطوری این روند ادامه پیدا می‌کنه الی آخر... مثلا برای اعدادی مثل ۳۷ بدون اینکه هیچ عددی پیدا بشه که ۳۷ بر اون بخشپذیر باشه، به خود ۳۷ می‌رسیم (یعنی به جایی می‌رسیم که i = 37 و j = 37) که این یعنی هیچ عددی کوچکتر از ۳۷ پیدا نکردیم که ۳۷ بهش بخشپذیر باشه، این یعنی ۳۷ یه عدد اوله. یعنی به جایی می‌رسه که:

۱. (j = 36, i = 37): آیا i == j؟ خیر - آیا i بر j بخشپذیر است؟ خیر، پس ادامه می‌دیم...
۲. (j = 37, i = 37): آیا i == j؟ بله، پس i یک عدد اول است. i رو چاپ کن!
۳. (j = 38, i = 37): ... (کارای بی‌دلیل...)

البته اگر بعد از خط ۹ یه دستور break نوشته بشه دیگه از ادامه‌ی حلقه‌ی داخلی در حالتی که عدد اول پیدا شده (مثل مثالی که الان زدم) جلوگیری می‌شه و این خیلی مفیده!

فکر می‌کنم طرز عملکرد متد myMethod الان دیگه قابل درکه.
موفق باشید.

Hossein8867
چهارشنبه 30 اردیبهشت 1394, 18:12 عصر
با سلام.جناب فدوی عزیز اگر بخواهم در کدهایی که شما نوشتید ابتدا اعداد اول بدست آمده را در یک آرایه کپی کنم و سپس توسط ثابت length مقدار آن ها را چاپ کنم چه کار باید انجام دهم؟در کدهایی که من نوشته بودم وقتی می خواستم از طریق ثابت length مقدار آرایه را چاپ کنم وقتی به اینصورت مینوشتم عدد 101 را نمایش میداد




int[] myArray = new int[i];
System.out.println(myArray.length[i]);




و وقتی یک متغیر به نام k میساختم و آن را درون if برابر با i می گذاشتم و مانند بالا به جای k,i را قرا میدادم عدد 97 را نمایش میداد در صورتیکه باید عدد 25 نمایش داده میشد.

بسیار از شما سپاسگزارم

محمد فدوی
چهارشنبه 30 اردیبهشت 1394, 18:54 عصر
اگر می‌خواید از همین کدی که نوشتم استفاده کنید می‌تونید با استفاده از ساختمان‌داده‌ای مثل List این‌کار رو بکنید:
public static void main(String[] args) {
List<Integer> list = new ArrayList();
for (int i = 2; i <= 100; i++) {
if (isPrime(i)) {
list.add(i);
}
}
Integer[] array = list.toArray(new Integer[0]);
}
یا اگه از جاوا ۸ استفاده می‌کنید می‌تونید این‌کار رو خیلی راحت‌تر و بهتر انجام بدید:
public static void main(String[] args) {
int[] array = IntStream.rangeClosed(2, 100).filter(i -> isPrime(i)).toArray();
}

اما اگر دنبال راه‌های بهتر هستید، برای پیدا کردن یه رنج از اعداد اول غربال اراتوستن (http://fa.wikipedia.org/wiki/%D8%BA%D8%B1%D8%A8%D8%A7%D9%84_%D8%A7%D8%B1%D8%A7% D8%AA%D9%88%D8%B3%D8%AA%D9%86) راه بهتریه.

Hossein8867
چهارشنبه 30 اردیبهشت 1394, 19:34 عصر
اگر می‌خواید از همین کدی که نوشتم استفاده کنید می‌تونید با استفاده از ساختمان‌داده‌ای مثل List این‌کار رو بکنید:
public static void main(String[] args) {
List<Integer> list = new ArrayList();
for (int i = 2; i <= 100; i++) {
if (isPrime(i)) {
list.add(i);
}
}
Integer[] array = list.toArray(new Integer[0]);
}
یا اگه از جاوا ۸ استفاده می‌کنید می‌تونید این‌کار رو خیلی راحت‌تر و بهتر انجام بدید:
public static void main(String[] args) {
int[] array = IntStream.rangeClosed(2, 100).filter(i -> isPrime(i)).toArray();
}

اما اگر دنبال راه‌های بهتر هستید، برای پیدا کردن یه رنج از اعداد اول غربال اراتوستن (http://fa.wikipedia.org/wiki/%D8%BA%D8%B1%D8%A8%D8%A7%D9%84_%D8%A7%D8%B1%D8%A7% D8%AA%D9%88%D8%B3%D8%AA%D9%86) راه بهتریه.

سلام.من تازه با آرایه ها آشنا شدم و با List آشناییت ندارم اگر امکان دارد بفرمایید می توان این کدها را مبتدی تر هم نوشت؟

محمد فدوی
چهارشنبه 30 اردیبهشت 1394, 21:32 عصر
اگه بخوای می‌تونی یه آرایه باطول به اندازه‌ی کافی بزرگ بسازی و اعداد اول پیدا شده رو توش قرار بدی... ولی در این صورت یه تعدادی از خونه‌های آرایه بی‌استفاده می‌مونه که یه نکته‌ی منفیه:
public static void main(String[] args) {
final int MAX_LENGTH = 100;

int[] array = new int[MAX_LENGTH];
int initialLen = 0;

for(int i = 2; i <= 100; i++) {
if(isPrime(i)) {
array[initialLen++] = i;
}
}
}
الان بعد از اینکه اعداد اول پیدا شدن، طول واقعی array برابر ۱۰۰ هست ولی فقط به اندازه‌ی initialLen توش عدد اول هست و بقیه‌ی خونه‌های بی‌استفاده با صفر پر شده‌ن.

Hossein8867
پنج شنبه 31 اردیبهشت 1394, 15:10 عصر
سلام.من کدها رو به صورتیکه شما گفتید می نویسم و کار می کند منتها من می خوام از ثابت length هم استفاده کنم.چه طوری میشه مقدار رو تو یه آرایه کپی کنم و توسط length آن را چاپ کنم؟

محمد فدوی
جمعه 01 خرداد 1394, 15:18 عصر
هنوزم بهترین راه برای داشتن یه آرایه‌ی به اندازه استفاده از ساختمان داده‌هایی مثل List هست ولی اگه بازم اصرار داری صرفا از آرایه‌ها استفاده کنی، می‌تونی بعد از استفاده از کدی که گذاشتم با استفاده از System.arraycopy اعداد اول پیدا شده رو به یه آرایه‌ی به اندازه کپی کنی:
int[] trimedArray = new int[initialLen];
System.arraycopy(array, 0, trimedArray, 0, initialLen);