02 هياكل البيانات: القوائم أحادية الرابط الجزء الثاني


مستوى المقال: متوسط

بسم الله الرحمن الرحيم 

السلام عليكم ورحمة الله وبركاته ...،

أولاً اعتذر جداً عن التأخر في طرح الشرح الذي كان من المفترض يكون بعد أسبوع من الموضوع السابق

تطرقنا في شرحنا السابق الى مفهوم القائمة أحادية الرابط وشرحنا استخداماته وطريقة عملها نظريا

شرحنا هذا سيكون عمليا من الدرجة الأولى بحيث سيكون كله حول الأكواد وتفصيلها.

 

١. إنشاء العقدة Node:

كما نعلم بأن Node هي الوحدة الأساسية لبناء قائمة أحادية الرابط أو القوائم بشكل عام ونستطيع بأن نصفها بأنها الحجر الذي يستخدم لبنائها.

لذلك يجب علينا بنائها ابتداءً.

public class SLLNode {
	public int info;
	public SLLNode next;
	
	public SLLNode(int i){
		this(i, null);
	}
	
	public SLLNode(int i, SLLNode n){
		this.info = i;
		this.next = n;
	}
}

هذا الكلاس والذي سمي بـ SSLNode هو الذي يصف لنا كل عقدة على حدى. 

وكل عقدة تتكون من info وهو المتغير الذي يحتوي على البيانات (المعلومة) وفي حالتنا هذه تكون البيانات من نوع int.

وكذلك next وهو عبارة عن الرابط الذي يصل العقدة الحالية بالعقدة التي تليها ومن الطبيعي أن يكون من نوع  SLLNode.

هذا الكلاس يحتوي على two Constructor وهما عبارة عن وظائف تستخدم لإنشاء العقد Nodes.

الأولى تستخدم لإنشاء عقدة لكنها لا ترتبط بأخرى كما نرى فيها فقد قمنا باستدعاء الميثود الثانية وقمنا بوضع null مكان الرابط.

أما الثانية فتنشأ عقدة ترتبط بأخرى. (قمت بتفصيلها في الموضوع السابق)

 

٢. إنشاء القائمة أحادية الرابط:

الكلاس السابق يمكننا من إنشاء عقدة واحدة لكن في هذا الكلاس سنتمكن من إنشاء قائمة كاملة تتكون من عدد من العقد Nodes.

أ. مؤشر لأول عنصر وآخر عنصر بالقائمة:

لكي نسهل عملية التنقل داخل القائمة سنقوم بإنشاء مؤشرين أحدهما يشير إلى أول عنصر بالقائمة (head: الرأس)،

والآخر يشير إلى آخر عنصر بالقائمة (tail: الذيل). هذين المؤشرين عبارة عن متغيريين من نوع SSNode.

protected SLLNode head, tail;

في بداية إنشاء القائمة (أو في حالة كانت القائمة خالية) فإن هذين العنصريين يكونان خاليين:

	public SLList(){
		head = tail = null;
	}

كما يتبين في هذه الـ Constructor.

 

ب. فحص القائمة إذا كانت خالية أو لا:

هذه الـ Method مهمة جداً ولها أستخدام في جل الـ Methods الأخرى، ومهمتها هي فحص إذا ما كانت القائمة خالية أو لا.

وتقوم بإرجاع قيمة Boolean إما true أو false.

	public boolean isEmpty(){
		return head == null;
		//or return tail == null;
	}

بكل بساطة في حال كان الرأس خالي فإن القائمة خالية كذلك، بالإمكان الإستعانة بالذيل كذلك فمن المستحيل أن يكون أحدهما خالي دون الآخر.

 

ب. إضافة عنصر جديد إلى الرأس (بداية القائمة):

	public void addToHead(int el){
    	head.next = head;
		head = new SLLNode(el);
		if (tail = null){ 
			tail = head;
		}
	}

أولا نجعل الرأس يشير إلى نفسه لكي نربط العنصر الجديد بالعنصر الأول السابق.

عندها نقوم بإنشاء عنصر Node ونجعله الرأس الجديد

في حالة كانت القائمة خالية نجعل الذيل يشير إلى نفس العنصر الذي يشير له الرأس.

ملاحظة: عندما يشير الرأس والذيل إلى نفس العنصر فهذا يعني بأن لدينا عنصر واحد فقط في القائمة.

 

ج. إضافة عنصر جديد إلى الذيل (نهاية القائمة):

	public void addToTail(int el){
		if(!isEmpty()){
			tail.next = new SLLNode(el);
			tail = tail.next;
		}else{
			head = tail = new SLLNode(el);
		}
	}

نفحص القائمة إذا كانت خالية:

- في حالة كانت غير خالية: ننشأ عنصر جديد ونجعل الذيل الحالي يشير إليه، ومن ثم نجعله الذيل الجديد.

- في حال كانت القائمة خالية: ننشأ عنصر جديد ونجعل الرأس والذيل يشيران إليه.

 

د. حذف العنصر الموجود بالرأس (أول عنصر):

	public int deleteHead(){
		int el = head.info;
		if(head == tail){
			head = tail = null;
		}else{
			head = head.next;
		}
		
		return el; 
	}

هذه الـ method تقوم بحذف العنصر الموجود بالرأس ومن ثم ترجع قيمته.

أولا نحفظ القيمة داخل متغير el لكي لا تضيع بعد حذف العنصر.

ومن ثم نفحص إذا كانت القائمة:

- تحتوي على عنصر واحد: فعندها نجعل الرأس والذيل يسيران إلى لا شيء null وتكون القائمة حينها خالية.

- تحتوي على أكثر من عنصر: فعندها نجعل العنصر الذي بعد الرأس هو الرأس الجديد، وفي هذه الحالة سيكون العنصر

لا يوجود ما يشير إليه ويحذف.

ومن ثم ترجع القيمة التي تم حذفها.

 

هـ- حذف العنصر الموجود بالذيل (آخر عنصر):

	public int deleteTail(){
		int el = tail.info;
		if(tail == head){
			head = tail = null;
		}else{
			SLLNode temp;
			for(temp = head; temp.next != tail; temp = temp.next);

			tail = temp; 
			tail.next = null;
		}
		
		return el;
	}

كما في السابق نحتفظ بقيمة العنصر لكي نقوم بإعادته بعد الإنتهاء من عملية الحذف لكن الحذف من الذيل ليس بسهولة الحذف من الرأس.

نفحص التالي:

- في حالة أن القائمة تحتوي على عنصر واحد فقط: فعندها نحذف القائمة كلها بجعل الرأس والذيل null.

- في حالة أن القائمة تحتوي على أكثر من عنصر:

أولا علينا أن نبحث عن العنصر السابق للذيل (العنصر قبل الأخير)، وذلك بأستخدام for loop قبلها علينا أن ننشأ مؤشر مؤقت باسم temp 

وفي بداية الـ loop نجعله يشير إلى الرأس، وننقله من عنصر إلى آخر إلى أن يصل إلى العنصر ما قبل الأخير وذلك بفحص إذا ما كان 

temp.next أي العنصر الذي يليه هو tail فعندها نكون وصلنا إلى العنصر ما قبل الأخير.

بعد أن نجد العنصر ما قبل الأخير نجعل الذيل الجديد ومن ثم نجعل الذيل يشير إلى null لكي يتم حذف العنصر الأخير تماماً.

 

و. طباعة جميع عناصر القائمة:

	public void printAll(){
		System.out.print("[");
		for(SLLNode temp = head; temp != null; temp = temp.next){
			System.out.print(temp.info + " ");
		}
		System.out.println("]");
	}

كما شرحنا سابقا نستخدم for loop للتنقل بين عناصر القائمة وطباعة قيمة كل عنصر على الشاشة.

 

ز. فحص وجود العنصر في القائمة أو لا:

	public boolean isInList(int el){
		if(isEmpty()){
			return false;
		}else{
			SLLNode temp;
			for(temp = head; temp.info != el && temp.next != null; temp = temp.next);
			return temp != null;
		}
	}

للبحث عن وجود قيمة داخل القائمة من عدمه يجب علينا أن نتنقل داخل القائمة عنصر بعنصر، وسنستخدم الأسلوب السابق

وهو باستخدام for loop. ولكن قبلها يجب علينا أن نتأكد من أن القائمة غير خالية.

الـ for loop ستتوقف في إحدى حالتين في حالة وجدة العنصر داخل القائمة وذلك ببطلان الشرط (tmep.info != el)

أو في حالة وصول temp إلى نهاية القائمة. 

عندها سنرجع القية المعاكسة لهذا الشرط (tmep != null) في حالة وصول الـ temp إلى نهاية القائمة بدون أن يجد العنصر

فعندا سيكون temp يساوي null وفي هذه الحالة سيرسل false أما في حالة إجاد العنصر فعندها temp لن يكون  null ويرسل true.

 

ح. حذف عنصر من القائمة:

public void delete(int el){
		if(!isEmpty() && isInList()){
			if(head == tail && head.info == el){
				head = tail = null;
			}else if(el == head.info){
				head = head.next;
			}else{
				SLLNode pre, temp;
				for(temp = head.next, pre = head; temp.info != el;
						pre = temp, temp = temp.next);
				if(temp != null){
					pre.next = temp.next;

					if(temp == tail){
						tail = pre;
					}

				}
			}
		}
	}

في حالة أردنا حذف عنصر من القائمة علينا أن نفكر في جميع الإحتمالات وهي كالتالي:

- هل القائمة غير خالية؟! وهل العنصر في القائمة ولتححق سنستخدم isEmpty و isInList، في حالة لم تكن القائمة خالية وكان العنصر بالقائمة ننتقل للخطوة التالية:

* هل القائمة تحتوي على عنصر واحد؟!: في هذه الحالة نقوم بحذف هذا العنصر ونجعل القائمة خالية.

* هل القائمة تحتوي على أكثر من عنصر والعنصر المراد حذفة بالرأس؟: عنذها نحذف الرأس كما أشرنا في الفقرة (د).

*الخيار الأخير هو أن العنصر موجود داخل القائمة: 

في هذه الحالة نحتاج للبحث عن العنصر بنفس الأسلوب السابق لكننا هنا على خلاف الخطوات السابقة نحتاج إلى متغيرين مؤقتين

أحدهما يشير إلى العنصر المراد حذفه والآخر يشير إلى العنصر الذي يسبقه. ولكي نقوم بذلك فعند إنشاء temp وهو العنصر المؤقت الذي سنبحث

عن طريقه للعنصر المراد حذفه نجعل pre العنصر الذي يسبقه وذلك كما يلي:

pre = head , temp = pre.next 

كما نعلم فنحن لسنا بحاجة لفحص الرأس فقد تأكدنا من أن العنصر ليس بالرأس. تنتهي for loop في حال إجاد العنصر المراد حذف مع العلم بأننا لن نصل إلى نهاية القائمة

لأننا تأكدنا من أن العنصر موجود في القائمة في الخطوة الأولى. وعند نهاية كل دورة من for loop نقوم بتحديث قيمتي pre and temp.

بعد ذلك نجعل الـ pre يشير للعنصر الذي يلي temp أي يشير للعنصر الذي بعد العنصر المراد حذفه عندها لن يكون هناك ما يشير إليه ويحذف.

** تأكد أخير في حال أن العنصر الذي حذفنها هو الأخير فعندها يجب أن نجعل الذيل يشير إلى null.

 

#شرح مفصل للـ for loop المستخدمة مع القوائم بشكل عام:

لأهميتها القصوى سوف أفصلها أكثر، إبتداءً بالشكل العام لها:

for (SLLNode temp = head; temp != null; temp = temp.next);

أولا نقوم بإنشاء متغير مؤقت ونسميه بأي أسم كان هذا المتغير في بداية الـ loop سيشير لأول عنصر بالقائمة

وهو الرأس head بعد ذلك يتأكد من تحقق الشرط وهو أن هذا المتغير لا يساوي null (أي أنه غير خالي)، ومن ثم

يحدث قيمة المتغير وذلك بجعله العنصر التالي له عن طريق (temp = temp.next) ومن ثم يقوم بالتأكد من الشرط مجدداً

هكذا حتى يصل إلى أن temp مساوي لـ tail وعندها يسنتقل للعنصر الذي يليه وهو في الحقيقة null لأنه tail.next دائما يساوي null

وهكذا تنتهي  for loop

ملاحظة: قمت بوضع ملفات للـ SLLNode and SLList classes في المرفقات تحتوي على تعليقات توضيحية.

 

أتمنى من الله أن أكون قد وفقت في تفصيل موضوعنا هذا

في حفظ الله إلى لقاء آخر

SLList.java

SLLNode.java

Abather

1


اراء المستخدمين


لاتوجد تعليقات لعرضها .



انشئ حساب جديد او قم بتسجيل دخولك لتتمكن من اضافه تعليق جديد

يجب ان تكون عضوا لدينا لتتمكن من التعليق

انشئ حساب جديد

سجل حسابك الجديد لدينا في الموقع بمنتهي السهولة .


سجل حساب جديد

تسجيل الدخول

هل تمتلك حساب بالفعل ؟ سجل دخولك من هنا.


سجل دخولك الان

Ads Belongs To This website

  • السلام عليكم ورحمة الله وبركاته 
    طرحنا مسابقة عالم البرمجة للنقاش الهادف ، و هدفنا إثراء المحتوى العربي في مجال البرمجة ، فاز معنا الطرح المتميز و المفيد حيث قام بتقييم المقالات وترقيتها من قبل فريق عالم البرمجة سنذكر بهذه المقالة الفائزين معنا ، و مقالاتهم ، و نشكرهم على ماقدموا من فائدة للجميع ، و إثراء المحتوى العربي في البرمجة.
    الفائزون في شهر Januray-2017
    @3zcs المقال الفائز:
    @3zcs المقال الفائز:
    @AMR0T  المقال الفائز:
    @وضاح العوني المقال الفائز:
    @يعرب المصطفى المقال الفائز:
    @Abdulrahman Hasan Agha المقال الفائز:
    @Omnyyah المقال الفائز:
    في الختام:
    هدفنا في موقع عالم البرمجة إثراء المحتوى العربي في مجال البرمجة ، و تعزيز حب المساعدة بين المبرمجين تستطيع كتابة ماتحب في ساحات النقاش ، و يمكن تكون احد الفائزين معنا  بمسابقة عالم البرمجة للنقاش الهادف فهي مازالت مستمره ايضا تستطيع مساعدة المبرمجين بالإجابة عن أسئلتهم ، و حل المشاكل التي تواجههم بقسم سؤال وجواب ؛ لتكون مرجع لبقية المبرمجين شعارنا في عالم البرمجة "إن في قضاء حوائج الناس لذة لا يَعرفها إلا من جربها، فافعل الخير مهما استصغرته فإنك لا تدري أي حسنة تدخلك الجنة." -ابن القيم-  وممكن تستفيد من
    حبيبي القارئ اعلم ان فريق عالم البرمجة يصب كل جهودة لمساعدة المبرمجين الذين يخصصون من وقتهم لنشر العلم المفيد ويساعدون الغير ويارب يقدرنا نوقف معكم ونساعدكم قد مانقدر.
    مستوى المقال: مبتدئ

    بواسطه Ali Majrashi , في

  • في هذه السلسلة – ان شاء الله – سأشرح أهم المواضيع في منهج نظرية الحوسبة  في أكثر من مقالة ولمن أراد الاطلاع أكثر فمرجعي الرئيسي هو كتاب
    An Introduction to FORMAL LANGUAGES and AUTOMATA
    للكاتب
    PETER LINZ
     
    المنهج مهم جداً لطلاب علوم الحاسب فهو يناقش مجموعة من المفاهيم النظرية البحتة والتي ساعدت في انشاء علوم الحاسب والخوارزميات وعلم المنطق والتي يجب على كل طالب استيعابها وفهمها .
    هناك ٣ محاور رئيسية لا بد من التحدث عنها قبل أن نسترسل في شرح أنواع القواعد والآلات الموجودة .
     
     
    أولاً : اللغات : 
     
    أغلب القواميس في جميع اللغات تعرف لنا اللغة بأنها نظام من التعبيرات لمجموعة من الأفكار والمفاهيم والحقائق وتضم عدداً من الرموز والقواعد لإنشاء الجمل والكلمات بشكل صحيح تحت هذه اللغة .
    نبدأها بمجموعة منتهية غير فارغة نسميها آلفابت Alphabet ويرمز لها برمز سيجما ∑ ومن خلال رمز واحد من الآلفابت يمكننا تكوين كلمة String والكلمة عبارة عن سلسلة منتهية من الرموز في الآلفابت .
     
    مثال : لدينا الآلفابت التالية
    ∑ = {a, b}
     
    فيمكننا انشاء كلمة ( نرمز لها بالرمز w ) تسمى abba أو a أو ba لأنها كلمات ضمن الألفابت الموجودة ، اذاً يمكننا عمل مجموعة لانهائية من الكلمات تحت آلفابت معينة .
    طول الكلمة يرمز له بالرمز |w| وهو رقم يساوي عدد الحروف في تلك الكلمة واذا كان طول الكلمة يساوي الصفر فيعني ذلك أن تلك الكلمة تسمى (ايبسلون أو لمدا ) ونرمز لها بالرمز  λ .
    λ|=0| .
     
     
    ثانياً : القواعد :
     
    تُعرَف القاعدة Rule عن طريق الرموز التالية
    G =(V, T, S, P)
     
    1- V : مجموعة من المتغيرات .
    2- T : مجموعة من الرموز المنتهية التي ننهي بها الكلمة .
    3- S : رمز البداية وهو ضمن T .
    4- P : القواعد التي نتبعها في صنع أي كلمة ضمن آلفابت معينة وهي قلب وأساس أي قاعدة .
     
     
    نفرض أن كل القواعد تأتي بهذا الشكل
    x -> y
    بحيث أن x تعني جميع المتغيرات والرموز المنتهية و y تحتوي على الرموز المنتهية والمتغيرات + الكلمة الفارغة λ .
     
     
    مثال توضيحي :
    G = { {S},{a,b},S,P}
    و القواعد في هذه اللغة P
    S -> aSb
    S -> λ
    أمثلة على الكلمات التي يمكننا اشتقاقها من هذه القاعدة
    ab , aabb , aaabbb وهكذا ، اذاً اللغة الخاصة بهذا القاعدة عباره عن مجموعة من a تتبعها مجموعة من b بنفس العدد .
     
    يمكننا كتابة اللغة بهذه الصيغة :

     
     
     ثالثاً : الآلات :
     
     الآلات Automata هي عبارة عن نموذج نظري للكمبيوترات الرقمية ، كل آلة لها ميكانيكا خاصة لقراءة المدخلات لكن لا تغيرها ويمكنها أيضاً تحديد نهاية وبداية كل كلمة أو مُدخل ويمكن أن يكون لها أجهزة تخزين وتحتوي على مجموعة من وحدات التحكم التي تتغير حالتها ومجموعة من دوال التغير المرتبطة بالمدخل والحالة الحالية للمدخل .
    بإذن الله في المقالات التالية سوف نناقش ٤ أنواع من الآلات وطريقة عملها والقواعد التي تقبلها ومايخصها بشكل مخصص .
    مستوى المقال: متوسط

    بواسطه Omnyyah , في

  • اللغة المستخدمة : swift 3
    البرنامج المستخدم : xcode 8
     
    في هذا الدرس سوف نتعلم طريقة تطبيق الsingleton design pattern في برنامج الxcode و في لغة برمجة swift 
    لكن في البداية لمأخذ مقدمة بسيطة عن الdesign pattern ، إذا ما هو الdesign pattern ؟
    الdesign pattern هي طريقة معينة أو نمط معين يستخدمه المبرمج لكتابة الكود البرمجي. لكن لماذا يستخدم هذه الطرق عوضا عن أي طريقة أخرى؟
    -في البرمجة وارد جدا أن تتعرض للمشكلات و أنا لا أتحدث هنا عن مشكلات الoutput فقط و إنما قد تواجه مشاكل معينة متعلقة بالطريقة التي قمت ببناء الكود عليها و هذه المشكلات غالبا ما تتواجد فيها خاصيتين رئيسيتين : 
     أن هذه المشكلات تحدث مع المبرمجين بشكل متكرر .  غالبا عند التعرض لأحد هذه المشكلات فإن إصلاحها سيكون مكلفا بمعنى أن المبرمج سيحتاج إلى إعادة كتابة كمية ليست بالقليلة من الأكواد لإصلاح المشكلة و الوصول إلى حل.  
    و لذلك يتم اسخدام طرق معينة لبناء الكود البرمجي تسمى design patterns.
    لنفرض أنك تعمل على تطبيق آيفون خاص بإدارة حسابات بنكية و لديك class باسم bankManager حيث يستخدم هذا الكلاس لإدارة كل العمليات المتعلقة بالبنك فعلى سبيل المثال يوجد به function خاصة بإيداع الأموال في حساب ما.. التي تتلقى باراميتر للid الخاص بالحساب و تتلقى بارامتر آخر لكمية المبلغ الذي سيتم إيداعه كذلك يحوي هذا الحساب function لسحب المبلغ و أخرى لتحويل المبلغ لحساب آخر.. الخ و بالتالي فإن هذا الclass سيحوي كل هذه الأوامر المهة التي ستستخدم في التطبيق.
    و هذه الأوامر سستستخدمها في كل الclasses التي ستقوم بإنشائها في تطبيقك بمعنى آخر.. ستحتاج لأن يكون لديك object من الكلاس bankManager في كل الclasses لديك في التطبيق لأنك ستحتاج حتما لاستخدام الأوامر المهمة في يحويها هذا الclass في أغلب الclasses في تطبيقك.
    لكن هل إنشاء object من الbankManager في كل الكلاسات التي لديك هي طريقة جيدة للعمل مع هذا الكلاس ؟
    بمعنى آخر هل من المناسب إنشاء عدد من الobjects من كلاس الbankManager أم يجب أن يكون لدينا فقط object واحد مشترك بين كل الكلاسات ؟
    الحقيقة أن إنشاء object واحد فقط مشترك بين كل الكلاسات هي الطريقة المثلى للتعامل مع ال objects من هذا الكلاس و لذلك فإنك بطريقة ما تحتاج لأن تجبر الكلاس على إنشاء object واحد فقط و إرجاع نفس الobject في كل مرة يتم فيها محاولة عمل object جديد من هذا الكلاس. لكن كيف يتم ذلك ؟ ذلك يتم من خلال ما يعرف بالsingleton object أو الsingleton design pattern
    إذا لنبدأ تطبيق ذلك عمليا :
    -في البداية افتح الxcode  قم بإنشاء مشروع جديد (create new xcode project > single view application )   و قم بتسميته Singleton.

     
    - الآن قم بعمل كلاس جديد و قم بتسميته bankManager.
    - في البداية و كما تعلم نحن بحاجة إلى استخدام object مشترك بين كل الكلاسات و لعل كلمة مشترك ستقودك الى التفكير ب static variable، بالفعل سنحتاج إلى عمل static variable لذلك توجه إلى الbankManager و قم بإضافة object من نوع الكلاس نفسه و هو الbankManager و قم بجعله static و لأن هذا الobject سيبدأ بقيمة nil ثم سيكون ذا قيمة من نوعBankManager عندما يتم استدعاؤه لذلك يجب أن يكون هذا الobject من نوع optional لذلك لا تنس إضافة ( ؟ ) في نهاية تعريفه.

     

    - الآن أصبح لدينا أوبجكت مشترك أو يمكن أن يكون مشتركا بين كل الكلاسات لأنه من نوع static. هل هذا يكفي ؟ بالطبع لا.
    من الذي سيحدد فيما إذا كان الobject قد تم إنشاؤه و بالتالي إعادته نفسه أو إنشاء object جديد في حال أن قيمة الobject في الحقيقة تساوي nil لذا هل يمكنك التفكير بالخطوة القادمة ؟ 
    - الحل هو عمل function تقوم بالمطلوب حيث ستقوم هذه الfunction بالتأكد أن الobject قد تم إنشاؤه و في حال كان الobject قد تم إنشاؤه بالفعل فإنها ستعيد هذا الobject bankManager الذي قمنا بإنشائه في الأعلى و إلا فإنها ستقوم بإنشائه إولا ثم إرجاعه بعد إنشائه. ولأن هذه الfunction سوف تقوم باستخدام object من نوع static إذا هي بحاجة أن تكون static كذلك و بالتالي ستكون الfunction كالتالي :
    -ملاحظة: من الشائع في برمجة - بعض الأحيان -  الآيفون تسمية هذه الfunction اسم مشابه لsharedObject أو sharedManager 

     
    - قد يرد إلى ذهنك الآن أننا سنستخدم هذه الfunction دائما إذا ما أردنا الوصول إلى الobject مما يعني أننا لن نصل إلى الobject مباشرة عن طريق استدعائه بشكل مباشر باستخدام BankManager.bankManager و الحقيقة أن استدعاءه بهذه الطريقة قد يسبب بعض المشاكل، مثلا: قد تقوم باستدعائه في أحد الكلاسات بهذه الطريقة و قيمته في ذلك التوقيت تساوي nil و فور محاولتك استخدام اي متغير أو function بداخل الكلاس BankManager فأن البرنامج سيتوقف لمحاولتك استدعاء function لعنصر قيمته في الحقيقة تساوي nil و لحل هذه المشكلة و حتى تقطع أي مجال لاستدعاء الobject بهذه الطريقة المباشرة قم بعمل الstatic object ليكون private و بالتالي سيظهر الكود بهذه الطريقة 

     
    - هل انتهى الأمر تماما؟ في الحقيقة ليس بعد. ماذا إن قمت خطأً بعمل object من كلاس الBankManager بالطريقة العادية لأنشاء Object من الكلاسات في سويفت ؟ أو افرض أنك تعمل في فريق من المبرمجين و قام مبرمج آخر باستكمال العمل من بعدك حينها ستحتاج إلى منعه من عمل object بالطريقة العادية حتى لا تسبب مشاكل أثناء العمل؟ لكن كيف يتم ذلك ؟ كل ما عليك فعله هو أن تجعل الfunction التي تثوم بعمل الobject بطريقة عادية لتكون من نوع private و بالتالي لن يكون بالإمكان استدعاءها خارج الكلاس و سيكون المبرمج مجبرا على استخدام الfunction المسماة sharedObject 
     
    و الآن هل انتهى الأمر ؟ 
    نعم انتهى الأمر هنا و أصبح الsingleton object جاهزا للاستخدام أخيرا.
    بقي الإشارة إلى نقطة مهمة، إن كنت من مبرمجيswift المتمرسين، فلعلك لاحظت أن بعض الclasses التي تقوم باستخدامها هي في الحقيقة تطبق الsingleton pattern و من هذه الكلاسات : 
    NSUserDefaults ---->  var userDefaults = NSUserDefaults.standardUserDefaults()
    UIScreen ----> var mainSecreen = UIScreen.mainScreen
    UIApplication ----> var application = UIApplication.sharedApplication
    -- لاحظ أن الوصول للshared object يمكن أن يكون عن طريق static method كما شرحنا في هذا الدرس و قد يكون عن طريق static variable 
     
    ختاما.. أتمنى أن أكون وفقت في الشرح و إيصال الفكرة و أسأل الله أن يجعله من العلم الذي يُنتفع به  .

    مستوى المقال: متوسط

    بواسطه يعرب المصطفى , في

  • بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    Hashing
     
    الكثير من الـ algorithms تستخدم في عملية البحث البسيطة عن Record معين أو Data معينة وسط الآلاف وأحيانا مئات الالاف من الملفات المخزنة في الذاكرة.
    العامل المهم في عملية اختيار الطريقة الممتازة تعتمد على الوقت وفعالية الجهاز المستخدم في عملية البحث ومدى كفائته. وواحدة من أفضل الطرق المستخدمة حالياً هي الـ Hashing .
    سنتعرف معاً في هذا المقال على :
    -          تعريف بسيط عن الـ Hashing.
    -          بعض الطرق المستخدمة في التعامل مع الـ Data في حالة التكرار في طريقة الـ Hashing.
    -          طريقة التطبيق في لغة برمجة Java.
     
    تعريف بسيط عن الـ Hashing:
    هي طريقة تستخدم لحفظ الملفات وتخزينها ومن ثم البحث عنها بأسرع طريقة ممكنة. تتميز هذه الطريقة عن غيرها بأنها قادرة على جلب الـ Data بوقت سريع جدا وسط ملفات ومعلومات كبيرة نوعاً ما مقارنة بغيرها من الطرق.
    هذه الطريقة تتميز بحفظ الـ Data في جدول بحيث يتم إعطاء كل معلومة رقم مميز يتم حفظه داخل جدول من البيانات ومن ثم يتم الوصول إليه مباشرة في حال الحاجة إلى البحث عنه. هذه الطريقة تتميز بقلة الوقت اللازم للقيام بهذه العملية بحيث يمكنك مباشرة معرفة ما إذا كان الملف الجاري البحث عنه موجود أو غير موجود دون الحاجة للبحث عنه داخل الذاكرة بأكملها.
    مثال :
    لنفرض بأن لدينا الأرقام التالية : 1-7-4-8-9-5 .
    إذا قمنا بحفظ هذه الأرقام داخل Array بشكل عشوائي مباشر على سبيل المثال فعند البحث عن رقم 9 ستضطر إلى البحث داخل الـ Array بالكامل لمعرفة ما اذا كان الرقم 9 موجود أو لا. تخيل بأن لديك أكثر من الف رقم او أكثر!! يمكنك تخيل الوقت الطويل الذي ستحتاجه للقيام بعملية البحث هذه.
    لكن باستخدام Hashing يمكننا مثلا تخزين هذه الأرقام داخل Array ولكن ليس بشكل عشوائي كما في السابق وإنما بالنسبة لباقي قسمة العدد على حجم الـ Array على سبيل المثال. لنتفرض بأننا انشأنا Array بحجم 9 خلايا، الصف الأول يوضح الـ index والصف الثاني يوضح العدد الموجود داخل هذا الـ index
    8 7 6 5 4 3 2 1 0 index                   value عند تعبئة هذه الـ Array سنستخدم العلاقة التالية : index = number % arrayLength. بمعنى آخر سيتم وضع الرقم داخل الخانة المعبرة عن باقي قسمة العدد على حجم الـ Array.
    فيكون الجدول بعد التعبئة بهذا الشكل
    8 7 6 5 4 3 2 1 0 index 8 7   5 4     1 9 value لاحظ بأن الرقم 9 وضع بخانة رقم 0 لان باقي قسمة 9 على حجم الـ Array سيعطيك صفر.
    الآن بامكانك مباشرة الذهاب حين البحث عن رقم 9 إلى الرقم المستخرج من الدالة index = number % arrayLength وهو صفر لتعرف ما اذا كان الرقم 9 موجود أو لا وبالتالي توفير الكثير من الوقت.
     
    بعض الطرق المستخدمة في التعامل مع الـ Data في حالة التكرار في طريقة الـ Hashing:
    في المثال السابق لم نصادف أي تكرار في قيمة باقي قسمة الارقام على حجم الـ array ولكن كيف من الممكن حل مشكلة تكرار القيم في حال وقوعها ؟
    هناك الكثير من الحلول التي من الممكن استخدامها لحل هذه المشكلة ولكن سيتم ذكر حل واحد في هذا المقال وسيتم الحديث عن باقي الحلول في مقالات قادمة إن شاء الله.
    1 - Separate Chaining : هذه الطريقة تعتمد على بناء ArrayList بشكل خاص أو أي Structure آخر بشكل عام داخل كل خلية في الـ Hash Table الموضح في الأمثلة السابقة.
    لنأخذ هذه الأعداد على سبيل المثال : 12 – 17 – 29 – 6 – 30 – 31 – 4 – 8 ولنقم بتوزيعها علىHash Table  بحجم 4 خلايا.

     
    في هذه الحالة يتم أولا معرفة الـ index المراد البحث داخله ومن ثم البحث داخل الـ ArrayList لمعرفة ما اذا كان الـ record المراد البحث عنه موجود أو غير موجود.
     
    طريقة التطبيق في لغة برمجة Java:
    هناك الكثير من الطرق لتطبيق فكرة الـ Hashing بواسطة الجافا ولكن سنقوم باتباع الطريقة الأسهل والأقل تعقيداً. سنحتاج إلى إنشاء كلاس List :
    List Class  : عبارة عن كلاس سيتم عمل objects منه  ويحتوي على الـ ArrayList المراد تخزين الـ Data فيها بالإضافة إلى Constructor.
    import java.util.ArrayList; public class List { private ArrayList<Integer> list = new ArrayList<Integer>(); //Constructor public List(){ } public ArrayList<Integer> getList(){ return list ; } }  
    نحتاج أيضاً لإنشاء test class للتأكد من صحة الـ HashTable 
    Test Class : في التيست كلاس سنقوم بإنشاء Array من كلاس List. لاحظ بأنه يجب عليك تعريف كل عناصر هذه الـ Array وبدون هذا التعريف سيظهر لك NullPointerException.
    //hash table List [] hashTable4 = new List [4] ; for (int i = 0 ; i<hashTable4.length ; i++) hashTable4[i] = new List();  
    ميثود print لطباعة الجدول 
    public static void print(List [] array){ for (int i = 0 ; i<array.length ; i++) System.out.println("index "+i+" : "+array[i].getList().toString()); }  
    ميثود getHashCode لمعرفة الـ index المناسب 
    public static int getHashCode(int num){ return num%4 ; }  
    نقوم بتخزين الأرقام في array لتسهيل عملية التصنيف والإدخال ومن ثم نقوم بإدخالها في object hashTable4
    //numbers we want to add int [] listOfNumbers = {12,17,29,30,6,31,4,8}; //add Numbers to the hash table for (int i = 0 ; i<listOfNumbers.length ; i++){ int index = getHashCode(listOfNumbers[i]); hashTable4[index].getList().add(listOfNumbers[i]); }  
    المخرج النهائي 

     
    مستوى المقال: متوسط

    بواسطه Abdulrahman Hasan Agha , في

  • السلام عليكم ورحمة الله وبركاته 
     
    اسأل الله ان يجعل اجازتكم سعيدة
     
    الدرس الثاني عشر : التغريد بواسطة الاردوينو .

     
    نبذة عن الدرس :
    في هذا الدرس سوف نقوم بعمل اتصال بين الاردوينو و تويتر وذلك لنستطيع إرسال تغريدات إلى تويتر
    من خلال الاردوينو وذلك بإستخدام مكتبة تسمح لاردوينو بالاتصال بتويتر وايضا نحتاج إن نستخدم  درع الواي فاي .
     
    متطلبات المشروع :

    أردوينو أونو

    درع الواي فاي (Wifi shield )
     
     
     
    التوكن (Token) :
    هو مجموعة من الرموز تمكن المكتبة من إستخدام حسابك بتويتر وذلك بعد الحصول على الصلاحيات منك .
     
    الحصول على التوكن :
    1-  قم بزيارة هذا الموقع.
    2- سجل الدخول إلى حسابك بتويتر.

    3- اضغط على زر إعطاء الصلاحيات لتطبيق.4- في نفس النافذة سوف يظهر التوكن الخاص بك. 

     
     
    الكود البرمجي :
    #include <SPI.h> #include <WiFi.h> #include <Twitter.h> //استدعاء المكتبة char ssid[] = ""; // اسم الشبكة المراد الاتصال بها char pass[] = ""; // كلمة السر الخاصة بالشبكة Twitter twitter(""); // التوكن الخاص بك char msg[] = ""; // هنا تقوم بكتابة التغريدة void setup() { delay(1000); WiFi.begin(ssid, pass); delay(10000); Serial.begin(9600); Serial.println("connect"); if (twitter.post(msg)) { int status = twitter.wait(&Serial); if (status == 200) { Serial.println("OK."); // عند ظهور هذه الرسالة تفيد بإن تم نشر التغريدة } else { Serial.print("failed : code "); // عند ظهور هذه الرسالة تفيد بحدوث خطا Serial.println(status); } } else { Serial.println("connection failed."); // هذه الرسالة تدل على حدوث خطا في الاتصال بالشكبة } } void loop() { }  
    رابط تحميل المكتبة Twitter.rar
    لمعرفة كيفية إضافة المكتبة للكود راجع هذا الدرس 
     
    تحدي :
    أجعل الاردوينو تتصل بـ ليد و عندما يتم إرسال التغريدة يضيء الليد .
     
     
    وإلى هنا نصل إلى ختام هذا الدرس 
    أتمنى إني أوضحت المعلومة بشكل المطلوب
    ونراكم إن شاء الله في دروس قادمة .
    مستوى المقال: مبتدئ

    بواسطه وضاح العوني , في

  • Ads Belongs To This website

    عالم البرمجة

    عالم البرمجة مقالات برمجة و دورات مجانية لإحتراف البرمجة هدفنا تبسيط البرمجة ونشرها بيد الكل بشكل ممتع ومتطور ومحدث بإستمرار لمواكبة جديد تطورات البرمجة الحديثة و المتقدمة بدون مقابل