المتجه (Vector) 3
مثال 1:
#include <iostream> #include <vector> using namespace std; int main() { vector<int> v(5); // Initialize vector v with size 5 int n = 0; // Prompt the user to enter vector elements cout << "Enter Vector Elements:\n"; for (size_t i = 0; i < v.size(); i++) { cin >> v[i]; // Read input into vector element at index i // Check if we're at the end of the vector if (i == v.size() - 1) { cout << "If you want to resize the list, enter the new size. Enter -1 to finish: "; cin >> n; if (n == -1) break; else v.resize(n); // Resize the vector to the new size entered by the user } } // Output the elements of the vector cout << "Vector elements are:\n"; for (size_t i = 0; i < v.size(); i++) { cout << v[i] << endl; // Output each element followed by a newline } return 0; }
إليك ما يفعله كل سطر من البرنامج:
- Vector v(5);: تهيئة المتجه v بالحجم 5، والذي يحتوي على عناصر تمت تهيئتها افتراضيًا (تتم تهيئة جميع العناصر إلى الصفر في هذه الحالة).
- يطالب المستخدم بإدخال عناصر المتجهات.
- يقرأ المدخلات من المستخدم إلى العناصر المتجهة باستخدام حلقة. بعد قراءة العنصر الأخير، يطلب الكود من المستخدم إما تغيير حجم المتجه أو الخروج من الحلقة عن طريق إدخال -1.
- إذا أدخل المستخدم حجمًا جديدًا، فسيتم تغيير حجم المتجه وفقًا لذلك باستخدام v.resize(n).
- إخراج عناصر المتجه بعد انتهاء الحلقة.
يسمح هذا الرمز للمستخدم بتغيير حجم المتجه ديناميكيًا أثناء الإدخال ثم يعرض عناصر المتجه.
مثال 2:
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> v = {5, 1, 2, 7, 0, 3}; // Initialize vector v with some unsorted integers sort(v.begin(), v.end()); // Sort the elements of the vector in ascending order // Output the sorted elements of the vector for (auto it : v) { cout << it << endl; // Output each sorted element followed by a newline } return 0; }
إليك ما يفعله كل سطر من البرنامج:
- Vector v = {5, 1, 2, 7, 0, 3};: تهيئة المتجه v بستة أعداد صحيحة بترتيب غير مصنف.
- Sort(v.begin(), v.end());: يفرز عناصر المتجه v بترتيب تصاعدي باستخدام خوارزمية std::sort. تتطلب وظيفة الفرز مكررين يحددان النطاق المراد فرزه، وهما v.begin() (يشير إلى العنصر الأول) و v.end() (يشير إلى عنصر واحد بعد العنصر الأخير).
- for (auto it : v) { … }: هذه حلقة for تعتمد على النطاق وتتكرر عبر المتجه المصنف v. وتتكرر عبر كل عنصر من عناصر المتجه v بترتيب تصاعدي.
- cout << it << endl;: داخل الحلقة، يتم طباعة كل عنصر من عناصر المتجه متبوعًا بخط جديد باستخدام cout.
وبالتالي فإن مخرجات هذا الكود ستكون:
0 1 2 3 5 7
يقوم بطباعة كل عنصر من عناصر المتجه المصنف v بترتيب تصاعدي، عنصر واحد في كل سطر.
مثال 3:
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int>v = {5, 1, 2, 7, 0, 3}; sort(v.rbegin(), v.rend()); for (auto it:v) { cout << it << endl; } return 0; }
إليك ما يفعله كل سطر من البرنامج:
- Sort(v.rbegin(), v.rend());: يفرز عناصر المتجه v بترتيب تنازلي باستخدام خوارزمية std::sort مع التكرارات العكسية. تتطلب دالة الفرز مكررين يحددان النطاق المراد فرزه، وهما v.rbegin() (يشير إلى العنصر الأخير، ويعامل على أنه الأول للفرز) وv.rend() (يشير إلى عنصر قبل العنصر الأول، ويعامل كآخر فرز).
إذن مخرجات هذا الكود ستكون:
7 5 3 2 1 0
يقوم بطباعة كل عنصر من عناصر المتجه المصنف v بترتيب تنازلي، عنصر واحد في كل سطر.
مثال 4:
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int>v = {5, 1, 2, 7, 0, 3}; reverse(v.begin(), v.end()); for (auto it:v) { cout << it << endl; } return 0; }
- Reverse(v.begin(), v.end());: عكس عناصر المتجه v باستخدام الخوارزمية std::reverse. تتطلب الدالة العكسية مُكرِّرين يحددان النطاق المراد عكسه، وهما v.begin() (يشير إلى العنصر الأول) وv.end() (يشير إلى عنصر واحد بعد العنصر الأخير).
وبالتالي فإن مخرجات هذا الكود ستكون:
3 0 7 2 1 5
يقوم بطباعة كل عنصر من عناصر المتجه المعكوس v، عنصر واحد في كل سطر.
مثال 5:
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> v = {5, 1, 2, 7, 0, 3}; // Initialize vector v with some integers // Find and output the minimum element in the vector cout << *min_element(v.begin(), v.end()) << endl; // Find and output the maximum element in the vector cout << *max_element(v.begin(), v.end()) << endl; // Find and output the minimum element in the vector excluding the last two elements cout << *min_element(v.begin(), v.end() - 2) << endl; return 0; }
إليك ما يفعله كل سطر من البرنامج:
- Vector v = {5, 1, 2, 7, 0, 3};: تهيئة المتجه v بستة أعداد صحيحة بالترتيب المحدد.
- cout << *min_element(v.begin(), v.end()) << endl;: ابحث عن الحد الأدنى للعنصر في المتجه v باستخدام خوارزمية std::min_element. تقوم الدالة min_element بإرجاع مكرر يشير إلى الحد الأدنى للعنصر، و* تلغي الإشارة إلى هذا المكرر للحصول على قيمة الحد الأدنى للعنصر. ثم تتم طباعة الحد الأدنى للعنصر متبوعًا بسطر جديد.
- cout << *max_element(v.begin(), v.end()) << endl;: كما هو مذكور أعلاه، يبحث هذا السطر عن الحد الأقصى للعنصر في المتجه v ويطبعه.
- cout << *min_element(v.begin(), v.end() – 2) << endl;: يبحث عن الحد الأدنى للعنصر في المتجه v باستثناء العنصرين الأخيرين. النطاق المستخدم للعثور على الحد الأدنى للعنصر هو من v.begin() إلى v.end() – 2 (باستثناء العنصرين الأخيرين). ثم تتم طباعة الحد الأدنى للعنصر متبوعًا بسطر جديد.
وبالتالي فإن مخرجات هذا الكود ستكون:
0 7 1
يقوم بطباعة الحد الأدنى للعنصر والحد الأقصى للعنصر والحد الأدنى للعنصر باستثناء العنصرين الأخيرين من المتجه v، متبوعًا كل منهما بسطر جديد.
مثال 6:
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int>v = {5, 1, 2, 7, 0, 3}; auto pair = minmax_element(v.begin(), v.end()); cout << *pair.first << endl; cout << *pair.second << endl; return 0; }
إليك ما يفعله كل سطر من البرنامج:
- auto Pair = minmax_element(v.begin(), v.end());: يبحث عن الحد الأدنى والحد الأقصى للعناصر في المتجه v باستخدام خوارزمية std::minmax_element. تقوم هذه الدالة بإرجاع زوج من التكرارات، حيث يشير المكرر الأول إلى الحد الأدنى للعنصر ويشير المكرر الثاني إلى الحد الأقصى للعنصر.
- cout << *pair.first << endl;: يُخرج قيمة الحد الأدنى للعنصر عن طريق إلغاء مرجعية pair.first.
- cout << *pair.sec << endl;: إخراج قيمة الحد الأقصى للعنصر عن طريق إلغاء pair.second.
وبالتالي فإن مخرجات هذا الكود ستكون:
0 7
يقوم بطباعة الحد الأدنى والحد الأقصى من عناصر المتجه v، متبوعًا بكل منها بخط جديد.
مثال 7:
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> v = {5, 1, 2, 7, 0, 3}; // Initialize vector v with some integers // Find the minimum element in the vector auto it = min_element(v.begin(), v.end()); // Sort the elements of the vector up to (but not including) the minimum element sort(v.begin(), it); // Output the sorted elements of the vector for (auto i : v) { cout << i << endl; // Output each sorted element followed by a newline } return 0; }
إليك ما يفعله كل سطر من البرنامج:
- auto it = min_element(v.begin(), v.end());: ابحث عن الحد الأدنى للعنصر في المتجه v باستخدام خوارزمية std::min_element. تقوم هذه الدالة بإرجاع مكرر يشير إلى الحد الأدنى من العناصر.
- Sort(v.begin(), it);: يفرز عناصر المتجه v حتى (ولكن لا يشمل) الحد الأدنى للعنصر الذي تم العثور عليه بواسطة min_element. يستخدم خوارزمية std::sort مع نطاق محدد بواسطة التكرارات، من v.begin() إليها. يؤدي هذا إلى فرز العناصر قبل العنصر الأدنى.
- for (auto i : v) { … }: هذه حلقة for تعتمد على النطاق وتتكرر عبر المتجه المصنف v. وتتكرر عبر كل عنصر من عناصر المتجه v بترتيب مفروز.
cout << i << endl;: داخل الحلقة، يتم طباعة كل عنصر مفروز i من المتجه متبوعًا بخط جديد باستخدام cout.
وبالتالي فإن مخرجات هذا الكود ستكون:
0 1 2 5 7
يقوم بطباعة كل عنصر من عناصر المتجه v حتى الحد الأدنى للعنصر، ويتم فرزه بترتيب تصاعدي، ويتبع كل منها سطر جديد.
مثال 8:
#include <iostream> #include <vector> #include <algorithm> using namespace std; bool GreaterThanThree(int i) { return i > 3; } int main() { vector<int> v = {5, 1, 2, 7, 0, 3}; // Initialize vector v with some integers // Sort the elements of the vector in ascending order sort(v.begin(), v.end()); // Find the first element greater than 3 using find_if with GreaterThanThree as the predicate auto it = find_if(v.begin(), v.end(), GreaterThanThree); // Output all elements greater than 3 for (; it != v.end(); it++) { cout << *it << endl; // Output each element greater than 3 followed by a newline } return 0; }
إليك ما يفعله كل سطر من البرنامج:
- bool GreaterThanThree(int i): يحدد دالة أصلية GreaterThanThree تُرجع صحيحًا إذا كان عدد الإدخال الصحيح i أكبر من 3.
- Vector v = {5, 1, 2, 7, 0, 3};: تهيئة المتجه v بستة أعداد صحيحة.
- Sort(v.begin(), v.end());: يفرز عناصر المتجه v بترتيب تصاعدي باستخدام خوارزمية std::sort.
- auto it = find_if(v.begin(), v.end(), GreaterThanThree);: يبحث عن العنصر الأول الأكبر من 3 في المتجه المصنف v باستخدام خوارزمية std::find_if مع الدالة الأصلية GreaterThanThree.
- for (; it != v.end(); it++) { … }: هذه حلقة for تتكرر على العناصر من العنصر الأول الأكبر من 3 حتى نهاية المتجه. يقوم بإخراج كل عنصر أكبر من 3 متبوعًا بسطر جديد باستخدام cout.
وبالتالي فإن مخرجات هذا الكود ستكون:
5 7
يقوم بطباعة كل عنصر من عناصر المتجه v أكبر من 3، متبوعًا بكل عنصر بسطر جديد.
مثال 9:
#include <iostream> #include <vector> #include <algorithm> using namespace std; bool GreaterThanThree(int i) { return i > 3; } int main() { int arr[] = {10, 20, 30, 40, 50, 60, 70}; vector<int> v(7); copy(arr, arr + 7, v.begin()); cout << "myvector contains: "; for (auto it:v) cout << it << " "; return 0; }
إليك ما يفعله كل سطر من البرنامج:
- int arr[] = {10, 20, 30, 40, 50, 60, 70};: تهيئة مصفوفة على النمط C تحتوي على سبعة أعداد صحيحة.
- Vector v(7);: تهيئة المتجه v بالحجم 7.
- Copy(arr, arr + 7, v.begin());: نسخ العناصر من مصفوفة النمط C إلى المتجه v باستخدام خوارزمية std::copy. تتطلب وظيفة النسخ ثلاث معلمات: مكررات البداية والنهاية للنطاق المصدر (هنا، arr و arr + 7 يمثلان المصفوفة بأكملها)، ومكررات البداية للنطاق الوجهة (هنا، v.begin()).
- cout << "myvector contains: "; يحتوي على رسالة تشير إلى بداية الإخراج.
- for (auto it : v) cout << it << ” “;: هذه حلقة for تعتمد على النطاق وتتكرر لكل عناصر المتجه v. وتقوم بإخراج كل عنصر من عناصر المتجه متبوعًا بمسافة.
وبالتالي فإن مخرجات هذا الكود ستكون:
myvector contains: 10 20 30 40 50 60 70
مثال 10:
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> from_vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; vector<int> to_vector(15); copy_backward(from_vector.begin(), from_vector.end(), to_vector.end()); cout << "to_vector contains: "; for (auto i: to_vector) cout << i << " "; return 0; }
إليك ما يفعله كل سطر من البرنامج:
- Vector from_vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};: تهيئة ناقل المصدر from_vector بعشرة أعداد صحيحة.
- Vector to_vector(15);: تهيئة المتجه المستهدف to_vector بالحجم 15.
- Copy_backward(from_vector.begin(), from_vector.end(), to_vector.end());: نسخ العناصر من المتجه المصدر from_vector إلى المتجه الهدف to_vector بترتيب عكسي باستخدام خوارزمية std::copy_backward. تتطلب وظيفة Copy_backward ثلاث معلمات: مكررات البداية والنهاية للنطاق المصدر (هنا، from_vector.begin() وfrom_vector.end() يمثلان المتجه بالكامل)، ومكرر النهاية لنطاق الوجهة (هنا، to_vector.end ()).
- cout << “to_vector contains: “;:يحتوي على رسالة تشير إلى بداية الإخراج.
- for (auto i : to_vector) cout << i << ” “;: هذه حلقة for تعتمد على النطاق وتتكرر عبر عناصر المتجه المستهدف to_vector. يقوم بإخراج كل عنصر من عناصر المتجه المستهدف متبوعًا بمسافة.
وبالتالي فإن مخرجات هذا الكود ستكون:
to_vector contains: 0 0 0 0 0 1 2 3 4 5 6 7 8 9 10
يقوم بطباعة كل عنصر من عناصر المتجه الهدف to_vector، والذي يحتوي على عناصر المتجه المصدر from_vector المنسوخة بترتيب عكسي، متبوعة بمسافة. يتم ترك العناصر الأولية لـ to_vector التي لم تتم الكتابة فوقها بواسطة عملية النسخ دون تغيير (تتم تهيئتها افتراضيًا إلى 0 في هذه الحالة).
مثال 11:
#include <iostream> #include <vector> #include <algorithm> #include <iterator> using namespace std; int main() { vector<int> v = {1, 2, 3, 4, 5}; // Initialize a vector v with five integers // Copy elements from the vector v to the standard output (cout) copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); return 0; }
إليك ما يفعله كل سطر من البرنامج:
- Copy(v.begin(), v.end(), ostream_iterator(cout, ” "));: نسخ العناصر من المتجه v إلى الإخراج القياسي (cout) باستخدام خوارزمية std::copy وstd: :ostream_iterator. تتطلب وظيفة النسخ ثلاث معلمات: مكررات البداية والنهاية للنطاق المصدر (هنا، v.begin() وv.end() يمثلان المتجه بأكمله)، ومكرر الإخراج (هنا، ostream_iterator(cout, ” “)) الذي يكتب كل عنصر منسوخ إلى الإخراج القياسي باستخدام فاصل مسافة.
وبالتالي فإن مخرجات هذا الكود ستكون:
1 2 3 4 5
خصائص المتجه
- Add -> Back -> O(1):
يشير هذا الخط إلى أن إضافة عنصر إلى الجزء الخلفي (النهاية) للمتجه له تعقيد زمني قدره O(1)، مما يعني أنها عملية في وقت ثابت. تمتلك المتجهات تخصيصًا ديناميكيًا للذاكرة، وعادةً ما تتضمن إضافة عنصر إلى الخلف إلحاق العنصر بنهاية كتلة الذاكرة المتجاورة الأساسية، وهو ما يمكن القيام به في وقت ثابت. - Delete -> Back -> O(1):
حذف عنصر من الجزء الخلفي (النهاية) للمتجه له أيضًا تعقيد زمني قدره O(1)، مما يعني أنها عملية في وقت ثابت. عادةً ما تتضمن إزالة العنصر الأخير تقليل حجم المتجه، ولا يلزم إعادة تخصيص أو تغيير العناصر. - Add -> Any Where -> O(N):
إن إضافة عنصر في أي مكان باستثناء الجزء الخلفي من المتجه، كما هو الحال في المقدمة أو في المنتصف، له تعقيد زمني قدره O(N). وذلك لأن إدراج عنصر في موضع عشوائي قد يتطلب نقل جميع العناصر اللاحقة لإفساح المجال للعنصر الجديد، الأمر الذي يستغرق وقتًا خطيًا يتناسب مع عدد العناصر المُزاحة. - Delete -> Any Where -> O(N):
وبالمثل، فإن حذف عنصر من أي مكان باستثناء الجزء الخلفي من المتجه له أيضًا تعقيد زمني قدره O(N). قد تتطلب إزالة عنصر من موضع عشوائي نقل جميع العناصر اللاحقة لملء الفجوة التي خلفها العنصر المحذوف، الأمر الذي يستغرق أيضًا وقتًا خطيًا يتناسب مع عدد العناصر المزاحة. - Access -> [] – at() -> O(1):
الوصول إلى عنصر في متجه بواسطة الفهرس باستخدام عامل الأقواس المربعة ([]) أو وظيفة العضو at() له تعقيد زمني قدره O(1). وهذا يعني أن الوصول إلى أي عنصر في المتجه يستغرق وقتًا ثابتًا بغض النظر عن حجم المتجه. توفر المتجهات وصولاً عشوائيًا في الوقت الثابت لأنها تخزن العناصر في كتلة ذاكرة متجاورة، مما يسمح بالوصول المباشر إلى أي عنصر من خلال فهرسه. - Search -> find() -> O(log N):
البحث عن عنصر في متجه مفروز باستخدام خوارزمية std::find() له تعقيد زمني قدره O(log N) عندما يتم فرز المتجه. وذلك لأن std::find() يقوم بإجراء بحث ثنائي على المتجه الذي تم فرزه، والذي يحتوي على تعقيد زمني لوغاريتمي. ومع ذلك، من المهم ملاحظة أنه إذا لم يتم فرز المتجه، فإن التعقيد الزمني للعثور على عنصر باستخدام std::find() سيكون O(N)، لأنه يقوم بإجراء بحث خطي.
الإيجابيات:
يتم تنفيذها كمصفوفات ديناميكية
السلبيات:
- إعادة توزيع مكلفة
- يتطلب الذاكرة المتجاورة