แถวลำดับ เป็นชุดลำดับของวัตถุที่เก็บข้อมูลชนิดเดียวกัน วัตถุแต่ละตัวในชุดลำดับ เรียกว่า สมาชิก (elements) ของแถวลำดับ วัตถุในแถวลำดับถูกกำกับด้วยค่าจำนวนเต็ม เรียกว่า ดัชนี (index) เริ่มตั้งแต่ค่าจำนวนเต็ม 0, 1, 2, 3, 4, … ตามลำดับ ในบางตำราจะเรียกดัชนีว่า ตัวห้อย (subscripts) เพื่อให้สอดคล้องกับค่าตัวห้อยในทางคณิตศาสตร์ เช่น $a_0, a_1, a_2$ เป็นต้น ค่าดัชนี หรือ ตัวห้อยเป็นตัวระบุตำแหน่งของสมาชิกในแถวลำดับ โดยจะถูกใช้เพื่อประกอบการคำนวณหาค่าเลขที่อยู่ของสมาชิกนั้นๆ การเข้าถึงสมาชิกของแถวลำดับโดยวิธีดังกล่าว เรียกว่า การเข้าถึงโดยตรง (direct access) กับแถวลำดับ
สมมติให้ แถวลำดับชื่อว่า a a[0] จะหมายถึง ชื่อของสมาชิกลำดับที่ 0 ของแถวลำดับ a ในทำนองเดียวกัน a[1] จะหมายถึง ชื่อของสมาชิกลำดับที่ 1 ของแถวลำดับ a กล่าวโดยทั่วไป สมาชิกตัวที่ i ของแถวลำดับ a จะชื่อ a[i-1] และ ถ้าแถวลำดับ a มีสมาชิก n ตัว จะประกอบด้วยสมาชิกชื่อ a[0], a[1], …และ a[n-1] ตามลำดับ
ในทางคอมพิวเตอร์ แถวลำดับ หมายถึง ชุดลำดับของเนื้อที่ที่ต่อเนื่องในหน่วยความจำ โดยแต่ละพื้นที่ถูกกำกับด้วยค่าดัชนี ตัวอย่างเช่น ถ้าแถวลำดับ a มีสมาชิก 5 ตัว โดยที่ a[0] มีค่าเป็น 11.11, a[1] มีค่าเป็น 33.33, a[2] มีค่าเป็น 55.55, a[3] มีค่าเป็น 77.77 และ a[4] มีค่าเป็น 99.9 การสำรองและจัดเก็บค่าของแถวลำดับ a จะแสดงได้ดังรูป 6-1
a[0] | a[1] | a[2] | a[3] | a[4] | |
---|---|---|---|---|---|
a | 11.11 | 33.33 | 55.55 | 77.77 | 99.99 |
รูป 6-1 การสำรองและกำหนดค่าของแถวลำดับ a
วิธีการกำหนดดัชนีของแถวลำดับให้เริ่มต้นที่ค่าจำนวนเต็ม 0 เรียกว่า การชี้ตำแหน่งดัชนีฐานศูนย์ (zero-based indexing) โดยค่าดัชนีจะชี้ตำแหน่งของสมาชิกในแถวลำดับ เช่น ดัชนีมีค่าเป็น 0 หมายถึง 0 ตัวจากจุดเริ่มต้น ดัชนีมีค่าเป็น 1 หมายถึง ถัดมา 1 ตัวจากจุดเริ่มต้น เป็นต้น
ข้อมูลชนิด int, long, หรือ float ที่แนะนำในบทที่ 2 เป็นชนิดข้อมูลแบบวัตถุเชิงเดี่ยว (scalar objects) ในขณะที่ แถวลำดับเป็นชนิดข้อมูลแบบวัตถุร่วม (composite objects) ที่ประกอบด้วยสมาชิกหลายตัว ที่มีค่าต่างๆ กัน เก็บภายใต้วัตถุเดียวกัน ตัวอย่าง 6.1 แสดงการกำหนดค่า และเรียกใช้งานสมาชิกในแถวลำดับ ซึ่งการจัดการเหมือนกับการทำงานกับวัตถุเชิงเดี่ยว
ตัวอย่าง 6.1 การเข้าถึงสมาชิกของแถวลำดับ
int main() { double a[3]; a[2] = 55.55; a[0] = 11.11; a[1] = 33.33; cout << "a[0] = " << a[0] << endl; cout << "a[1] = " << a[1] << endl; cout << "a[2] = " << a[2] << endl; }
ทดสอบโปรแกรม
a[0] = 11.11 a[1] = 33.33 a[2] = 55.55
คำสั่งบรรทัดแรกในโปรแกรม เป็นการประกาศ แถวลำดับชื่อ a ที่มีสมาชิกจำนวน 3 ตัว เก็บข้อมูลชนิด double สามคำสั่งถัดมาเป็นการกำหดนค่าให้กับสมาชิกของแถวลำดับ a ตัวที่มีค่าดัชนีเป็น 2, 0 และ 1 ตามลำดับ ส่วนสามคำสั่งสุดท้าย เป็นการนำค่าสมาชิกของแถวลำดับ a มาแสดงผลทางจอภาพตามลำดับ ตั้งแต่ตัวที่ 0, 1 และ 2
ตัวอย่าง 6.2 การพิมพ์สมาชิกของแถวลำดับ
int main() { const int SIZE = 5; // defines size for array = 5 double a[SIZE]; // declares array a as type double cout << "Enter " << SIZE << " numbers: \t"; for (int i=0; i < SIZE; i++) cin >> a[i]; cout << "In reverse order: "; for (int i=SIZE-1; i >= 0; i--) cout << "\t" << a[i]; }
ทดสอบโปรแกรม เมื่อป้อนค่า 11.11, 33.33, 55.55, 77.77 และ 99.99 ตามลำดับ
Enter 5 numbers: 11.11 33.33 55.55 77.77 99.99 In reverse order: 99.99 77.77 55.55 33.33 11.11
บรรทัดแรกเป็นการประกาศตัวคงที่ size มีค่าเป็น 5 ดังนั้น การประกาศแถวลำดับ a ในบรรทัดที่ 2 จึงมีผลให้สำรองแถวลำดับ a ให้มีสมาชิก 5 ตัว เก็บข้อมูลชนิด double คำสั่งวนรอบคำสั่งแรก เป็นการวนรอบเพื่อให้ผู้ใช้ป้อนค่าผ่านทางแป้นพิมพ์ แล้วนำมาเก็บที่สมาชิกของแถวลำดับ a เริ่มที่ตัวที่ 0, 1, .. ส่วนคำสั่งวนรอบตัวที่สอง เป็นการวนรอบเพื่อนำค่าสมาชิกของแถวลำดับ a มาแสดงผล โดยแสดงผลจากสมาชิกตัวสุดท้าย (ตัวที่ 4) ย้อมมาที่ตัวแรก (ตัวที่ 0)
รูปแบบการประกาศแถวลำดับ สรุปได้ดังนี้
type array-name [ array-size ]
โดยที type หมายถึง ชนิดข้อมูลของสมาชิกในแถวลำดับ array-name คือ ชื่อของแถวลำดับ และ array-size คือ ขนาด (จำนวนสมาชิก) ของแถวลำดับ ในภาษา C++ ขนาดของสมาชิกของแถวลำดับต้องระบุด้วยค่าจำนวนเต็มบวกคงที่ ซึ่งอาจจะเป็นค่าคงที่ในตัวอย่างที่ 6.1
double a[3];
หรือ ตัวคงที่ในตัวอย่างที่ 6.2
double a[size];
โดยส่วนใหญ่ ผู้เขียนโปรแกรมมักประกาศจำนวนสมาชิกของแถวลำดับด้วยตัวคงที่ เพื่อที่จะสามารถใช้ตัวคงที่ดังกล่าวในคำสั่งการวนรอบ เพื่อดำเนินการกับแถวลำดับ
ในภาษา C++ ผู้เขียนโปรแกรมสามารถกำหนดค่าเริ่มต้นให้กับสมาชิกแต่ละตัวของแถวลำดับได้โดยประกาศชุดค่าเริ่มต้น (initializer list) เช่น
float a[] = { 22.2, 44.4, 66.6 };
การประกาศแถวลำดับที่ไม่ระบุจำนวนสมาชิก จะมีการสำรองสมาชิกเท่ากับจำนวนค่าที่ระบุ โดยค่าที่ระบุในชุดค่าเริ่มต้น จะถูกกำหนดให้กับสมาชิกของแถวลำดับ เริ่มตั้งแต่ตัวที่ 0, 1, … ตามลำดับ จากการประกาศข้างต้น จะได้แถวลำดับ ชื่อ a ที่มีสมาชิก 3 ตัว โดยที่ a[0] = 22.2, a[1] = 44.4 และ a[2] = 66.6
ตัวอย่าง 6.3 การกำหนดค่าเริ่มต้นให้กับแถวลำดับ
int main() { float a[] = { 22.2, 44.4, 66.6}; int size = sizeof(a)/sizeof(float); for (int i=0; i < size; i++) cout << "\ta[" << i << "] = " << a[i] << endl; }
ทดสอบโปรแกรม
a[0] = 22.2 a[1] = 44.4 a[2] = 66.6
คำสั่งบรรทัดแรก ประกาศแถวลำดับ a ให้มีสมาชิก 3 ตัว พร้อมกับกำหนดค่าเริ่มต้นให้กับแถวลำดับดังที่ได้อธิบายไปก่อนหน้านี้ ฟังก์ชัน sizeof ในบรรทัดที่สอง เป็นฟังก์ชันคำนวณหาขนาดของวัตถุ โดย sizeof (a) จะคืนขนาดของแถวลำดับ a จากตัวอย่างได้ 12 ไบต์ sizeof (float) คืนค่าขนาดของข้อมูลชนิด float ซึ่งก็คือ 4 ไบต์ ดังนั้น นิพจน์ sizeof (a) / sizeof (float) จะได้จำนวนสมาชิกของแถวลำดับ a
ในภาษา C++ การกำหนดค่าให้กับแถวลำดับ โดยมีสมาชิกบางตัวไม่มีการกำหนดค่าให้ สมาชิกเหล่านั้นจะถูกกำหนดให้มีค่าเป็น 0 เรียกว่า zeroed out เช่น
float a[7] = { 55.5, 66.6, 77.7 };
จะได้ a[0] = 55.5, a[1] = 66.6, a[2] = 77.7 ในขณะที่ a[3], a[4], a[5] และ a[6] จะมีค่าเป็น 0
ตัวอย่าง 6.4 การกำหนดค่าเริ่มต้นให้แถวลำดับแบบไม่ครบจำนวน
int main() { float a[7] = { 22.2, 44.4, 66.6}; int size = sizeof(a)/sizeof(float); for (int i=0; i < size; i++) cout << "\ta[" << i << "] = " << a[i] << endl; }
ทดสอบโปรแกรม
a[0] = 22.2 a[1] = 44.4 a[2] = 66.6 a[3] = 0 a[4] = 0 a[5] = 0 a[6] = 0
จากตัวอย่าง ผู้เขียนโปรแกรมสามารถนำมาประยุกต์ใช้ เพื่อทำการกำหนดค่าให้สมาชิกทุกตัวในแถวลำดับให้มีค่าเป็น 0 ได้ โดยใช้ชุดค่าเริ่มต้นแบบว่าง (empty initializer list) เช่น
float a[ ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; float a[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; float a[9] = { 0 };
คำสั่งประกาศแถวลำดับทั้งสามคำสั่งมีผลเหมือนกัน คือ จะได้แถวลำดับชื่อ a ที่มีสมาชิก 9 ตัว เก็บค่า float โดยทุกตัวจะมีค่าเริ่มต้นเป็น 0
การกำหนดค่าให้สมาชิกในแถวลำดับ ผู้เขียนโปรแกรมไม่สามารถกำหนดค่าเกินกว่าจำนวนสมาชิกที่ถูกสำรอง เช่น
float a[3] = {22.2, 44.4, 66.6, 88.8}; // ERROR: too many values
คำสั่งข้างต้นเป็นการประกาศแถวลำดับที่ผิดรูปแบบในภาษา C++
ถ้าผู้เขียนโปรแกรมไม่ทำการกำหนดค่าให้กับแถวลำดับ สมาชิกของแถวลำดับจะเริ่มทำงานด้วยค่าที่เป็นขยะ (garbage) โดยจะเป็นค่าของข้อมูลเดิมที่ตำแหน่งเดียวกันในหน่วยความจำ และถ้าผู้เขียนนำค่าของสมาชิกในแถวลำดับมาใช้งานโดยไม่มีการกำหนดค่าให้กับแถวลำดับเสียก่อน การทำงานของโปรแกรมจะเกิดข้อผิดพลาดขึ้น
ตัวอย่าง 6.5 แถวลำดับที่ไม่ได้กำหนดค่าเริ่มต้น
int main() { const int SIZE = 4; float a[SIZE]; for (int i=0; i < SIZE; i++) cout << "\ta[" << i << "] = " << a[i] << endl; }
ทดสอบโปรแกรม
a[0] = 6.06633e-39 a[1] = 1.4013e-45 a[2] = 3.58732e-43 a[3] = 1.4013e-45
หมายเหตุ ผลรันของโปรแกรมตัวอย่างอาจได้ค่าไม่เท่าในแต่ละครั้งของการประมวลผล ขึ้นกับว่าก่อนการประมวลผล พื้นที่ที่ใช้ในการประมวลผลมีข้อมูลเดิมเป็นเท่าไร
ให้สังเกตุว่า การกำหนดค่าเริ่มต้นให้แถวลำดับต่างจากการกำหนดค่าให้แถวลำดับ ผู้เขียนโปรแกรมสามารถกำหนดค่าเริ่มต้นให้กับแถวลำดับด้วยชุดค่าเริ่มต้นได้ แต่ไม่สามารถกำหนดค่าให้กับแถวลำดับด้วยค่าในแถวลำดับอื่น เช่น
float a[7] = {11.1, 22.2, 33.3 }; float b[7]; b = a; // ERROR: arrays cannot be assigned
จากตัวอย่าง การกำหนดค่าเริ่มต้นให้แถวลำดับ a สามารถทำได้ แต่การนำค่าในแถวลำดับ a มากำหนดให้กับแถวลำดับ b ไม่สามารถทำได้ การกำหนดค่าเริ่มต้นให้กับแถวลำดับต้องกระทำ โดยใช้ชุดค่าเริ่มต้นเท่านั้น เช่น
float b[7] = a; // ERROR: arrays cannot be used as initializer
เป็นการกำหนดค่าเริ่มต้นที่ไม่ถูกต้องในภาษา C++ เนื่องจาก กำหนดค่าเริ่มต้นด้วยค่าของแถวลำดับ การกำหนดค่าสามารถกระทำได้กับสมาชิกในแถวลำดับเท่านั้น เช่น
b[2] = 22.5;
ในภาษาคอมพิวเตอร์บางตัว เช่น ภาษาปาสคาล (PASCAL) จะมีการตรวจสอบว่าค่าดัชนีที่มีการอ้างอิงถึงในแถวลำดับ จะต้องไม่เกินที่จำนวนสมาชิกที่แถวลำดับได้สำรองไว้ แต่ในภาษา C++ ไม่มีการตรวจสอบดังกล่าว เพราะฉะนั้น โปรแกรมสามารถเรียกใช้ดัชนีที่มีค่าเกินขอบเขตที่ประกาศไว้ได้ ผลที่ตามมา คือ การทำงานของโปรแกรมอาจผิดพลาด โดยที่ไม่มีการฟ้องข้อผิดพลาดในระหว่างการประมวลผลเลย จึงเป็นหน้าที่ที่ผู้เขียนโปรแกรมต้องพึงระวังที่จะไม่เรียกใช้ดัชนีเกินกว่าที่ได้ประกาศไว้
ตัวอย่าง 6.6 การระบุค่าดัชนีเกินขอบเขตที่ประกาศ
int main() { const int SIZE = 4; float a[SIZE] = {33.3, 44.4, 55.5, 66.6}; for (int i=0; i < 7; i++) // ERROR: index is out of range cout << "\ta[" << i << "] = " << a[i] << endl; }
ทดสอบโปรแกรม
a[0] = 33.3 a[1] = 44.4 a[2] = 55.5 a[3] = 66.6 a[4] = 9.36657e-39 a[5] = 6.01484e-39 a[6] = 1.4013e-45
ค่าของ a[4], a[5] และ a[6] ในตัวอย่าง เป็นค่าขยะที่เหลือค้างไว้ในหน่วยความจำก่อนหน้านี้ การยอมให้ผู้เขียนโปรแกรมระบุค่าดัชนีเกินขอบเขตอาจก่อให้เกิดข้อผิดพลาดที่คาดไม่ถึงได้ ดังจะแสดงในตัวอย่าง 6.7
ตัวอย่าง 6.7 ข้อผิดพลาดจากการระบุดัชนีเกินขอบเขต
int main() { float a[3] = {22.2, 44.4, 66.6}; float x = 11.1; cout << "x = " << x << endl; a[3] = 88.8; //ERROR: index is out of bound cout << "x = " << x << endl; }
ทดสอบโปรแกรม
x = 11.1 x = 88.8
คำสั่งประกาศตัวแปร x ถูกประกาศต่อจากคำสั่งประกาศตัวแปรแถวลำดับ a มีผลให้เกิดการสำรองเนื้อที่ขนาด 4 ไบต์ให้ x ต่อเนื่องจากพื้นที่ 12 ไบต์ที่ได้สำรองให้กับแถวลำดับ a ดังรูป 6-2 ผลที่ตามมา ตำแหน่งของตัวแปร x อยู่ที่เดียวกับตำแหน่งของ a[3] ทำให้เมื่อกำหนดค่า a[3] เป็น 88.8 จึงมีผลให้ค่าของ x เปลี่ยนเป็น 88.8
ข้อผิดพลาดในตัวอย่างเกิดขึ้นในช่วงเวลาของการประมวลผล โดยที่การทำงานของโปรแกรมสามารถดำเนินต่อเนื่องจนสิ้นสุดคำสั่งในโปรแกรม ข้อผิดพลาดดังกล่าวแฝงตัวอยู่อย่างเงียบๆ และถ้าผู้ใช้ไม่ทำการตรวจสอบ ผู้ใช้ก็จะไม่ทราบว่ามีข้อผิดพลาดเกิดขึ้น ตัวอย่างถัดไปแสดงข้อผิดพลาดอันเนื่องมาจากสาเหตุเดียวกัน แต่ในการประมวลผล ระบบปฏิบัติการสามารถตรวจพบข้อผิดพลาดดังกล่าว เนื่องจาก ในโปรแกรมมีการระบุดัชนีที่เกินขอบเขตมากเกินไป ทำให้ตำแหน่งของสมาชิก a[3333] ที่คำนวณได้อยู่นอกเหนือพื้นที่ที่ระบบปฏิบัติการสำรองให้กับโปรแกรม
ตัวอย่าง 6.8 การระบุดัชนีเกินขอบเขตมากๆ
int main() { float a[3] = {22.2, 44.4, 66.6}; float x = 11.1; cout << "x = " << x << endl; a[3333] = 88.8; //ERROR: index is out of bound cout << "x = " << x << endl; }
ทดสอบโปรแกรม
x = 11.1 error occurs
การประกาศตัวแปรแถวลำดับ float a[ ] บอกโปรแกรมแปลโปรแกรมให้ทราบข้อมูล 2 อย่าง คือ ชื่อของแถวลำดับชื่อว่า a มีสมาชิกเก็บข้อมูลชนิด float โดยชื่อ a จะเก็บค่าเลขที่อยู่ที่ตำแหน่งเริ่มต้นของแถวลำดับ ในการส่งแถวลำดับเป็นพารามิเตอร์เพื่อไปทำงานในฟังก์ชัน ผู้เขียนโปรแกรมต้องส่งข้อมูลเลขที่อยู่ (ผ่านชื่อ) และ ชนิดข้อมูล (type) ของแถวลำดับ โดยเลขที่อยู่จะเป็นตำแหน่งเริ่มต้นของสมาชิกตัวแรกใน แถวลำดับ (ตัวที่ 0) เพื่อใช้ในการคำนวณหาตำแหน่งของสมาชิกตัวใดๆ ของแถวลำดับ ชนิดข้อมูลจะบอกให้ทราบว่า จะมีการนำเอาข้อมูลในแถวลำดับมาใช้งานได้อย่างไร ส่วนขนาด (จำนวนสมาชิก) ของแถวลำดับ จะถูกส่งไปในรูปแบบชัดเจน (explicit) กล่าวคือ ในรูปของพารามิเตอร์ตัวหนึ่ง
ตัวอย่าง 6.9 การส่งแถวลำดับไปทำงานในฟังก์ชันเพื่อหาผลรวมของค่าสมาชิก
int sum(int [], int); int main( ) { int a[] = {11, 33, 55, 77}; int size = sizeof(a)/ sizeof(int); cout << "sum(a,size) = " << sum(a,size) << endl; } int sum(int a[], int n) { int sum = 0; for (int i=0; i < n; i++) sum += a[i]; return sum; }
ทดสอบโปรแกรม
sum(a,size) = 176
เมื่อมีการเรียกใช้ฟังก์ชัน sum ( ) ข้อมูลของแถวลำดับ a จะถูกส่งผ่านแบบโดยค่า ( passing by value) ไปยังฟังก์ชัน sum ( ) แต่เนื่องจากค่าที่ส่งเป็นค่าของเลขที่อยู่ของแถวลำดับ a ทำให้ในฟังก์ชันสามารถเปลี่ยนค่าสมาชิกแต่ละตัวของแถวลำดับ a ได้ เหมือนกับเป็นการผ่านค่าโดยการอ้างอิง (pass by reference) ค่าเลขที่อยู่ที่ส่งผ่านไปยังฟังก์ชัน จะถูกใช้เพื่อคำนวณค่าเลขที่อยู่ของสมาชิกตัวอื่นๆ ในแถวลำดับ เช่น ถ้าเลขที่อยู่ของแถวลำดับเป็น 1000 และ สมาชิกของแถวลำดับเก็บข้อมูลชนิด float (4 ไบต์) สมาชิกตัวที่ 3 (ดัชนีเป็น 2) มีค่าเลขที่อยู่เป็น 1000 + 2 x 4 = 1008
ตัวอย่าง 6.10 ฟังก์ชันนำเข้าและส่งออกข้อมูลในแถวลำดับ
void read(int [], int&); void print(int [], int); const int MAXSIZE = 100; int main( ) { int a[MAXSIZE] = {0}, size; read(a,size); cout << "The array has " << size << " elements: "; print(a, size); } void read(int a[], int& n) { cout << "Enter integers. Terminate with 0: \n"; n = 0; do { cout << "a[" << n << "]: "; cin >> a[n]; } while (a[n++] != 0 && n < MAXSIZE); --n; //don't count the zero } void print(int a[], int n) { for (int i=0; i < n; i++) cout << a[i] << " "; }
ทดสอบโปรแกรม เมื่อป้อนค่า 11, 22, 33, 44 และ 0 ตามลำดับ
Enter integers. Terminate with 0: a[0]: 11 a[1]: 22 a[2]: 33 a[3]: 44 a[4]: 0 The array has 4 elements: 11 22 33 44
ฟังก์ชัน read ( ) ต้องการเปลี่ยนค่าของแถวลำดับ a และ ค่าพารามิเตอร์ size โดย size จะต้องมีการผ่านข้อมูลโดยการอ้างอิง เพื่อที่ฟังก์ชัน read ( ) จะได้เปลี่ยนค่าได้ ในขณะที่ a เป็นแถวลำดับ จะมีการผ่านข้อมูลโดยค่า (เลขที่อยู่) ฟังก์ชันสามารถใช้ค่าเลขที่อยู่ในการคำนวณหาตำแหน่งของสมาชิกในแถวลำดับ เพื่อเปลี่ยนแปลงค่าได้
ตัวอย่าง 6.11 พิมพ์ตำแหน่งของแถวลำดับ
int main( ) { int a[] = {22, 44, 66, 88}; cout << "a = " << a ; //the address of a[0] }
ทดสอบโปรแกรม
a = 0065FDF4
หมายเหตุ การอ้างอิงชื่อของแถวลำดับ จะได้ตำแหน่งที่อยู่ของแถวลำดับนั้น (ตำแหน่งสมาชิกตัวแรก) ถ้าต้องการอ้างอิงถึงสมาชิกในแถวลำดับ ต้องอ้างอิงโดยใช้ชื่อแถวลำดับประกอบกับค่าดัชนี เช่น a[0], a[1] หรือ a[i]
ขั้นตอนวิธีการสืบค้นข้อมูลแบบเชิงเส้น (The Linear Search Algorithm) เป็นวิธีการค้นหาข้อมูลที่จะสืบค้นตั้งแต่ตัวแรกในแถวลำดับไปทีละตัว จนถึงตัวสุดท้ายในแถวลำดับนั้น
ตัวอย่าง 6.12 วิธีการสืบค้นข้อมูลแบบเชิงเส้น
int index(int, int [], int); int main( ) { int a[] = {22, 44, 66, 88, 44, 66, 55}; cout << "index(44,a,7) = " << index(44,a,7) << endl ; cout << "index(50,a,7) = " << index(50,a,7) << endl ; } int index(int x, int a[], int n) { for (int i=0; i < n; i++) if (a[i] == x) return i; return n; //x not found }
ทดสอบโปรแกรม
index(44,a,7) = 1 index(50,a,7) = 7
จากตัวอย่าง ฟังก์ชัน index ( ) จะทำการวนรอบ เพื่อเปรียบเทียบค่าของตัวแปร x กับสมาชิกในแถวลำดับ เริ่มตั้งแต่ตัวที่ 0 ไปทีละตัว และ ถ้าพบว่ามีตัวใดที่ค่าเท่ากันกับค่าใน x จะคืนค่าตำแหน่งดังกล่าวกลับไป แต่ถ้าตรวจสอบค่าสมาชิกครบทุกตัว แล้วไม่พบว่ามีตัวใดมีค่าเท่ากับค่าใน x ก็จะคืนค่าจำนวนสมาชิกของแถวลำดับกลับไป
ขั้นตอนวิธีการจัดเรียงข้อมูลแบบฟองสบู่ (The Bubble Sort Algorithm) เป็นวิธีการจัดเรียงข้อมูลที่ง่ายที่สุด โดยมีแนวคิดที่จะหาตัวที่มีค่ามากที่สุดไปเก็บไว้ที่สมาชิกตัวท้ายสุด ตัวที่มากรองลงมาไปไว้ที่สมาชิกตัวก่อนสุดท้าย ไปเรื่อยๆ ทีละตัว ซึ่งเปรียบได้กับฟองอากาศ (bubble) ที่ลอยขึ้นทีละฟอง วิธีนี้จะอาศัยการทำงานซ้ำๆ กัน ในการจัดเรียง โดยที่ ถ้าแถวลำดับมีสมาชิกจำนวน n ตัว จะมีการทำงานทั้งสิ้น n-1 รอบ ในรอบแรก จะเปรียบเทียบเพื่อหาตัวมากที่สุดไว้ที่สมาชิกตัวที่ n-1, รอบที่ 2 เปรียบเทียบตัวที่เหลือเพื่อหาตัวมากที่สุด เก็บไว้ที่ตัวที่ n-2, ทำไปเรื่อยๆ รอบที่ n-1 จะเปรียบเทียบ 2 ตัวที่เหลือ เก็บค่าที่มากกว่าไว้ที่ตัวที่ 1 และ เหลือค่าน้อยที่สุดเก็บไว้ที่ตัวที่ 0
ฟังก์ชัน sort ( ) ในตัวอย่าง ใช้คำสั่งการวนรอบซ้อนกัน 2 คำสั่ง ลูปนอกเป็นการหาค่ามากที่สุดของจำนวนสมาชิกที่เหลือในรอบที่ i ใดๆ ส่วนลูปใน จะใช้การเปรียบเทียบสมาชิก 2 ตัวที่อยู่ต่อเนื่องกัน ถ้าพบว่า ตัวก่อนหน้ามีค่ามากกว่าตัวถัดไป จะทำการสลับค่าของสมาชิกทั้งสอง ด้วยวิธีการเปรียบเทียบดังกล่าว จะได้ค่าตัวมากค่อยๆ ลอยไปเก็บในสมาชิกตำแหน่งท้ายของแถวลำดับ
ตัวอย่าง 6.13 วิธีการจัดเรียงข้อมูลแบบฟองสบู่
void print(float [], int); void sort(float [], int); void swap(float&, float&); int main( ) { float a[] = {55.5, 22.5, 99.9, 66.6, 44.4, 88.8, 33.3, 77.7}; print(a,8); sort(a,8); print(a,8); } void print(float a[], int n) { for (int i=0; i < n; i++) cout << a[i] << " "; cout << endl; } void sort(float a[], int n) { //bubble sort : for (int i = 1; i < n; i++) //bubble up max{0,..,n-1} for (int j = 0; j < n-1; j++) if (a[j] > a[j+1]) swap(a[j],a[j+1]); //INVARAINT: a[n-1-i..n-1] is sorted } void swap(float& x, float& y) { // exchanges the values of x and y: float temp = x; x = y; y = temp; }
ทดสอบโปรแกรม
55.5 22.5 99.9 66.6 44.4 88.8 33.3 77.7 22.5 33.3 44.4 55.5 66.6 77.7 88.8 99.9
ขั้นตอนวิธีการสืบค้นแบบทวิภาค (The Binary Search Algorithm) เป็นวิธีการสืบค้นที่ใช้กลยุทธ์แบ่งแยกเพื่อชัยชนะ (divide and conquer strategy) โดยจะแบ่งข้อมูลออกเป็นสองส่วน แล้วเลือกกระทำเฉพาะกับส่วนที่เป็นเป้าหมายไปเรื่อยๆ จนกว่าจะได้คำตอบที่ต้องการ การใช้วิธีการสืบค้นแบบทวิภาค ค้นหาข้อมูลในแถวลำดับ จะทำได้ก็ต่อเมื่อ ข้อมูลในแถวลำดับมีการจัดเรียงลำดับอยู่แล้ว
วิธีการสืบค้นแบบทวิภาคจะทำงานได้เร็วกว่าวิธีการสืบค้นแบบเชิงเส้น สำหรับข้อมูล n ตัว วิธีการสืบค้นแบบเชิงเส้นจะใช้การทำงานทั้งสิ้นไม่เกิน n ครั้ง ในขณะที่ วิธีการสืบค้นแบบทวิภาคจะใช้การทำงานทั้งสิ้นเพียงไม่เกิน log (n) + 1 ครั้ง ในกรณี ค่าที่สืบค้นมีอยู่ในแถวลำดับมากกว่า 1 ที่ วิธีการสืบค้นแบบเชิงเส้นจะพบข้อมูลตัวที่อยู่ตำแหน่งก่อนเสมอ ในขณะที่ วิธีการสืบค้นแบบทวิภาคอาจจะพบข้อมูลตัวไหนก็ได้
ตัวอย่าง 6.14 วิธีการสืบค้นแบบทวิภาค
int index(int, int [], int); int main( ) { int a[] = {22, 33, 44, 55, 66, 77, 88}; cout << "index(44,a,7) = " << index(44,a,7) << endl; cout << "index(60,a,7) = " << index(60,a,7) << endl; } int index(int x, int a[], int n) { //PRECONDITION: a[0] <= a[1] <= ... <= a[n-1] //binary search: int lo = 0, hi = n-1, i; while (lo <= hi) { i = (lo + hi)/2; // the average of lo and hi if (a[i] == x) return i; if (a[i] < x) lo = i+1; // continue search in a[i+1..hi] else hi = i-1; // continue search in a[lo..i-1] } return n; // x was not found in a[0..n-1] }
ทดสอบโปรแกรม
index(44,a,7) = 2 index(60,a,7) = 7
จากตัวอย่าง ในแต่ละรอบของคำสั่ง while จะทำการเปรียบเทียบสมาชิกตัวที่อยู่ตรงกลาง a[i] (เมื่อ i = (lo + hi) / 2) ของแถวลำดับย่อย a [lo..hi] เมื่อค่า lo และ hi เริ่มต้นเป็น 0 และ n-1 ตามลำดับ ถ้าพบว่าสมาชิกตัวกลางมีค่าเท่ากับค่าของตัวแปร x จะส่งค่าตำแหน่ง i คืนกลับไป แต่ถ้าค่าในสมาชิกตัวกลางน้อยกว่าค่า x หมายความว่า ค่า x จะไม่อยู่ในแถวลำดับ a [lo..i] โปรแกรมจะเลื่อนค่า lo ไปที่ตำแหน่ง i+1 ในทางกลับกัน ถ้าค่าในสมาชิกตัวกลางมากกว่าค่า x หมายความว่า ค่า x จะไม่อยู่ในแถวลำดับ a [i..hi] โปรแกรมจะเลื่อนค่า hi ไปที่ตำแหน่ง i-1 จะเห็นว่า ในแต่ละรอบจะลดจำนวนสมาชิกในแถวลำดับ a ได้ครึ่งหนึ่ง ลูปจะดำเนินไปเรื่อยๆ จนกว่าจะพบค่าที่เท่ากับค่าใน x หรือ ค่าของ hi น้อยกว่าค่าของ lo ซึ่งหมายความว่า ไม่พบค่า x ในแถวลำดับ a
การทำงานของโปรแกรมตัวอย่าง 6.14 จะถูกต้องก็ต่อเมื่อ แถวลำดับ a มีการจัดเรียงลำดับของสมาชิกจากค่าน้อยไปหาค่ามาก ถ้าแถวลำดับ a ไม่มีคุณสมบัติดังกล่าว โปรแกรมจะทำงานให้ไม่ถูกต้อง ในบางกรณี โปรแกรมอาจเกิดการวนรอบไม่รู้จบ ตัวอย่าง 6.15 แสดงการตรวจสอบแถวลำดับว่า มีการเรียงลำดับจากค่าน้อยไปมากหรือไม่
ตัวอย่าง 6.15 พิจารณาว่าแถวลำดับมีการจัดเรียงหรือไม่
bool isNondecreasing(int [], int); int main( ) { int a[] = {22, 44, 66, 88, 44, 66, 55}; cout << "isNondecreasing(a,7) = " << isNondecreasing(a,7) << endl; cout << "isNondecreasing(a,4) = " << isNondecreasing(a,4) << endl; } bool isNondecreasing(int a[], int n) { //returns true if a[0] <= a[1] <= ... <= a[n-1] for (int i=1; i < n; i++) if (a[i] < a[i-1]) return false; return true; }
ทดสอบโปรแกรม
isNondecreasing(a,7) = 0 isNondecreasing(a,4) = 1
ฟังก์ชัน isNondecreasing ( ) จะทำการวนรอบ เพื่อตรวจสอบว่าค่าสมาชิก 2 ค่าที่อยู่ต่อเนื่องกัน มีคู่ใดที่สมาชิกตัวหลังมีค่ามากกว่าสมาชิกตัวก่อนหน้าหรือไม่ ถ้ามีจะคืนค่า false เพราะนั่นหมายความว่าข้อมูลไม่ได้เรียงจากค่าน้อยไปมาก แต่ถ้าตรวจสอบสมาชิกทุกคู่ที่อยู่ต่อเนื่องกัน ไม่พบเงื่อนไขดังกล่าว แสดงว่าแถวลำดับมีการเรียงจากน้อยไปมาก จะคืนค่า true
ตัวอย่าง 6.16 ใช้ฟังก์ชัน assert ( ) กับการจัดการผลการตรวจสอบการจัดเรียงข้อมูล
int index(int, int [], int); bool isNondecreasing(int [], int); int main( ) { int a[] = {22, 33, 44, 55, 66, 77, 88, 60}; cout << "index(44,a,7) = " << index(44,a,7) << endl; cout << "index(44,a,8) = " << index(44,a,8) << endl; cout << "index(60,a,8) = " << index(60,a,8) << endl; } int index(int x, int a[], int n) { //PRECONDITION: a[0] <= a[1] <= ... <= a[n-1] //binary search: assert(isNondecreasing(a,n)); int lo = 0, hi = n-1, i; while (lo <= hi) { i = (lo + hi)/2; // the average of lo and hi if (a[i] == x) return i; if (a[i] < x) lo = i+1; // continue search in a[i+1..hi] else hi = i-1; // continue search in a[lo..i-1] } return n; // x was not found in a[0..n-1] } bool isNondecreasing(int a[], int n) { //returns true if a[0] <= a[1] <= ... <= a[n-1] for (int i=1; i < n; i++) if (a[i] < a[i-1]) return false; return true; }
ทดสอบโปรแกรม
index(44,a,7) = 2 Assertion failed:isNondecreasing(a,n),file ex6_16.cpp,line 15 Abnormal program termination
โปรแกรมตัวอย่างเป็นการโปรแกรมที่ปรับปรุงจากโปรแกรมตัวอย่าง 6.14 โดยนำฟังก์ชัน isNondecraesing ( ) ที่พัฒนาในตัวอย่า 6.15 มาใช้ตรวจสอบเงื่อนไขการจัดเรียงข้อมูลจากน้อยไปมาก และ ใช้ฟังก์ชัน aasert ( ) ในการจัดการกับผลการตรวจสอบอีกที่หนึ่ง
ฟังก์ชัน assert ( ) อยู่ในไฟล์ส่วนหัวชื่อ <cassert> จะทำการนำค่า bool ที่รับเข้ามาพิจารณาว่า ถ้าเป็น false จะแสดงข้อความข้อผิดพลาด (error message) ทางจอภาพ แล้วจบการทำงาน แต่ถ้าเป็น true จะไม่มีผลใดๆ เกิดขึ้น จากตัวอย่าง เมื่อเรียก index(44,a,7) เมื่อพิจารณา isNondecreasing(a,7) พบว่าแถวลำดับ a[0..7] มีการเรียงข้อมูลจากน้อยไปมาก ทำให้ไม่มีผลการทำงานใดๆ เกิดขึ้นจากฟังก์ชัน assert และเมือสืบค้นต่อ ก็พบว่า ค่า 44 พบในสมาชิกที่มีดัชนีเป็น 2 นั่นเอง แต่เมื่อเรียก index(44,a,8) เมื่อพิจารณา isNondecreasing(a,8) พบว่าแถวลำดับ a[0..8] ไม่ได้เรียงข้อมูลจากน้อยไปมาก โดย a[7] (มีค่า 60) มีค่าน้อยกว่า a[6] (มีค่า 80) ฟังก์ชัน assert จึงแสดงข้อความข้อผิดพลาดทางจอภาพ แล้วจบการทำงานของโปรแกรม
ข้อมูลชนิด enum สามารถนำมาใช้เป็นดัชนีของแถวลำดับได้ ดังแสดงในตัวอย่าง 6.17
ตัวอย่าง 6.17 การใช้ข้อมูลชนิด enum เป็นดัชนีของแถวลำดับ
int main() { enum Day {SUN, MON, TUE, WED, THU, FRI, SAT}; float high[SAT+1] = {88.3,95.0,91.2,89.9,91.4,92.5,86.7}; for (int day = SUN; day <= SAT; day++) cout << "The high temperature for day " << day << " was " << high[day] << endl; }
ทดสอบโปรแกรม
The high temperature for day 0 was 88.3 The high temperature for day 1 was 95 The high temperature for day 2 was 91.2 The high temperature for day 3 was 89.9 The high temperature for day 4 was 91.4 The high temperature for day 5 was 92.5 The high temperature for day 6 was 86.7
จากตัวอย่าง กำหนดจำนวนสมาชิกของแถวลำดับเป็น SAT+1 เนื่องจาก ในการประกาศข้อมูล enum ชื่อ Day จะได้ค่า SAT เป็นจำนวนเต็ม 6 ดังนั้น แถวลำดับ high จึงมีจำนวนสมาชิกทั้งสิ้น 7 ตัว คำสั่งวนรอบมีการวนรอบตั้งแต่ค่า SUN ซึ่งก็คือ 0 เพิ่มทีละ 1 จนถึงค่า SAT ซึ่งก็คือ 6 รวมทั้ง 7 รอบ เพื่อพิมพ์ค่าสมาชิกของแถวลำดับ high ทางจอภาพ
ข้อมูลชขนิด enum ในภาษา C++ เป็นรูปแบบข้อมูลชนิดหนึ่งที่ผู้เขียนโปรแกรมสามารถกำหนดขึ้นมาเอง เพื่อใช้งานในโปรแกรม เช่น
enum Color {RED, ORANGE, YELLOW, GREEN, BLUE, VIOLET};
เป็นคำสั่งประกาศข้อมูลชนิดใหม่ชื่อ Color ที่เก็บค่าได้ตามค่าที่ประกาศไว้ในชุดข้อมูล ผู้เขียนโปรแกรมสามารถใช้งานชนิด Color ได้ในโปรแกรม ดังตัวอย่าง
Color shirt = BLUE; Color car[] = {GREEN, RED, BLUE, RED}; Float wavelength[VIOLET+1] = { 420, 480, 530, 570, 600, 620};
คำสั่งแรก เป็นการประกาศตัวแปรชื่อ shirt ให้เก็บข้อมูลชนิด Color โดยกำหนดให้มีค่าเริ่มต้นเป็น BLUE (4) คำสั่งที่สอง ประกาศตัวชื่อ car เป็นแถวลำดับของข้อมูลชนิด Color จำนวน 4 ตัว มีค่าเริ่มต้น car[0] เป็น GREEN (3), car[1] เป็น RED (0), car[2] เป็น BLUE (4) และ car[3] เป็น RED (0) คำสั่งสุดท้าย ประกาศตัวแปรชื่อ wavelength เป็นแถวลำดับของข้อมูลชนิด float จำนวน 6 ตัว โดย wavelength[0] ถึง wavelength[5] มีค่าเป็น 420, 480, 530, 570, 600 และ 620 ตามลำดับ
ในภาษา C++ ผู้เขียนโปรแกรมสามารถตั้งชื่อใหม่ให้กับชนิดข้อมูลที่มีอยู่แล้ว ได้โดยใช้คำสำคัญ typedef กำกับชื่อที่ตั้งขึ้นใหม่ เรียกว่า การนิยามชนิดข้อมูล (type definition) ตามรูปแบบ
typedef type alias;
โดยที่ type หมายถึง ชนิดข้อมูลเดิมที่ต้องการประกาศชื่อเพิ่ม และ alias คือ ชื่อชนิดข้อมูลชื่อใหม่ที่ตั้งขึ้นมา ให้สังเกตุว่า ชนิดข้อมูลยังคงมีชนิดเดียว แต่ผู้เขียนโปรแกรมสามารถเรียกใช้งานได้ 2 ชื่อ เช่น
typedef long integer; typedef double real; integer n = 22; const real PI = 3.141592653589793;
สองคำสั่งแรก เป็นการประกาศชื่อให้กับชนิดข้อมูลใหม่ โดยตั้งชื่อชนิด integer ใหม่ให้กับข้อมูลชนิด long และชนิด real ให้กับชนิด double ดังนั้น ในโปรแกรม การอ้างอิงชื่อ integer จะหมายถึงข้อมูลชนิด long และ การอ้างอิงชื่อ real จะหมายถึงข้อมูลชนิด double ดังนั้น คำสั่งที่สาม จะทำการสำรองตัวแปรชื่อ n ให้เก็ข้อมูลชนิด long มีค่าเริ่มต้นเป็น 22 และในคำสั่งสุดท้าย จะเกิดตัวคงที่ชื่อ PI เก็บข้อมูลชนิด double มีค่าเป็น 3.141592653589793
สำหรับข้อมูลแบบแถวลำดับ มีรูปแบบการนิยามชนิดข้อมูล ดังนี้
typedef element-type alias[];
โดยที่ element-type หมายถึง ชนิดข้อมูลของสมาชิกในแถวลำดับ และ alias คือ ชื่อชนิดข้อมูลใหม่ที่ตั้งขึ้นมา เช่น
typedef float Sequence[];
จากการประกาศข้างต้น จะได้ Sequence เป็นชื่อชนิดข้อมูลแบบแถวลำดับ ที่มีสมาชิกเป็นข้อมูลชนิด float เครื่องหมาย [ ] ในการนิยามชนิดข้อมูล บอกให้รู้ว่าเป็นข้อมูลแบบแถวลำดับ ไม่ได้เป็นส่วนหนึ่งของชื่อชนิดข้อมูลแต่อย่างใด
Sequence a = {11.1, 22.2, 33.3};
เป็นคำสั่งประกาศตัวแปร a เป็นแถวลำดับของข้อมูลชนิด float ที่มีการสำรองสมาชิก 3 ตัว มีค่าเริ่มต้นเป็น 11.1, 22.2 และ 33.3 ตามลำดับ
ตัวอย่าง 6.18 ตัวอย่างการจัดเรียงข้อมูลด้วยวิธีฟองสบู่กับการนิยามชนิดข้อมูลแถวลำดับ
typedef float Sequence[]; void print(Sequence, int); void sort(Sequence, int); void swap(float&, float&); int main( ) { Sequence a = {55.5,22.2,99.9,66.6,44.4,88.8,33.3,77.7}; print(a,8); sort(a,8); print(a,8); } void print(Sequence a, int n) { for (int i=0; i < n; i++) cout << a[i] << " "; cout << endl; } void sort(Sequence a, int n) { for (int i = 1; i < n; i++) for (int j = 0; j < n-1; j++) if (a[j] > a[j+1]) swap(a[j],a[j+1]); } void swap(float& x, float& y) { float temp = x; x = y; y = temp; }
ทดสอบโปรแกรม
55.5 22.2 99.9 66.6 44.4 88.8 33.3 77.7 22.2 33.3 44.4 55.5 66.6 77.7 88.8 99.9
โปรแกรมมีการนิยามชนิดข้อมูลชื่อ Sequence มาแทนชนิดมูลแบบแถวลำดับของข้อมูลชนิด float ดังนั้น คำสั่งประกาศตัวแปร ให้เก็บข้อมูลชนิด Sequence ในโปรแกรม จึงหมายถึง การประกาศตัวแปรเป็นแถวลำดับของข้อมูลชนิด float นั่นเอง
แถวลำดับที่พบในตัวอย่างที่ผ่านมาเป็นแถวลำดับหนึ่งมิติ (ในแนวเชิงเส้น) ในทางคอมพิวเตอร์สมาชิกของแถวลำดับสามารถเป็นข้อมูลชนิดใดก็ได้ รวมถึงข้อมูลแถวลำดับเอง แถวลำดับที่มีสมาชิกเป็นแถวลำดับ เรียกว่า แถวลำดับหลายมิติ (multidimensional arrays) แถวลำดับที่มีสมาชิกเป็นแถวลำดับหนึ่งมิติ เรียกว่า แถวลำดับสองมิติ (two-dimensional arrays) ส่วนแถวลำดับที่มีสมาชิกเป็นแถวลำดับสองมิติ เรียกว่า แถวลำดับสามมิติ (three-dimensional arrays) ตัวอย่างการประกาศข้อมูลแถวลำดับ เช่น
double a[4][5];
เป็นคำสั่งประกาศแถวลำดับ a เป็นแถวลำดับของข้อมูลชนิด double ที่มี 4 แถว แต่ละแถวมี 5 สดมภ์ (สมาชิก 5 ตัว) รวมมีสมาชิกทั้งสิ้น 20 ตัว
double a[3][4][5];
เป็นคำสั่งประกาศแถวลำดับ a เป็นแถวลำดับ ของ double ที่มีมิติเป็น 3, 4 และ 5 ตามลำดับ การกำหนดค่าให้กับสมาชิกในแถวลำดับ ทำได้ดังนี้
a[2][3] = 99.99;
เป็นคำสั่งกำหนดค่าให้กับสมาชิกของแถวลำดับ a ในแถวที่มีดัชนีเป็น 2 (แถวที่ 3) สดมภ์ที่มีดัชนีเป็น 3 (สดมภ์ที่ 4) ให้มีค่าเป็น 99.99
ตัวอย่าง 6.19 การกำหนดค่าและแสดงผลข้อมูลในแถวลำดับสองมิติ
void read(int a[][5]); void print(int a[][5]); int main( ) { int a[3][5]; read(a); print(a); } void read(int a[][5]) { cout << "Enter 15 integers, 5 per row: \n"; for (int i=0; i < 3; i++) { cout << "Row " << i << ": "; for (int j=0; j < 5; j++) cin >> a[i][j]; } } void print(int a[][5]) { for (int i=0; i < 3; i++) { for (int j=0; j < 5; j++) cout << " " << a[i][j]; cout << endl; } }
ทดสอบโปรแกรม เมื่อป้อนค่า (44, 77, 33, 11, 44), (60, 50, 30, 90, 70) และ (85, 25, 45, 45, 55) ตามลำดับ
Enter 15 integers, 5 per row: Row 0: 44 77 33 11 44 Row 1: 60 50 30 90 70 Row 2: 85 25 45 45 55 44 77 33 11 44 60 50 30 90 70 85 25 45 45 55
ให้สังเกตุว่า ในการประกาศพารามิเตอร์ของแถวลำดับหลายมิติเป็นในฟังก์ชัน ผู้เขียนโปรแกรมไม่จำเป็นต้องระบุจำนวนสมาชิกของมิติแรก แต่ต้องระบุจำนวนสมาชิกในแต่ละมิติที่เหลือ เนื่องจาก ค่าจำนวนสมาชิกในมิติถัดไปจะถูกใช้ในการคำนวณหาตำแหน่งของสมาชิกตัวดังกล่าวในแถวลำดับ ในความเป็นจริง แถวลำดับหลายมิติมีรูปแบบโครงสร้างเหมือนกับแถวลำดับหนึ่งมิติ คือ เป็บชุดลำดับของข้อมูลเรียงต่อเนื่องกันในหน่วยความจำ เพียงแต่ แถวลำดับหลายมิติจะมีการแบ่งกลุ่มของชุดข้อมูลเป็นกลุ่มย่อยๆ เพื่อประโยชน์ในการใช้งานในโปรแกรม เช่น ใช้อ้างอิงข้อมูลตาราง หรือ เมทริกซ์ เป็นต้น
ตัวอย่าง 6.20 การส่งผ่านแถวลำดับสองมิติให้กับฟังก์ชัน
const int NUM_STUDENTS = 3; const int NUM_QUIZZES = 5; typedef int Score[NUM_STUDENTS][NUM_QUIZZES]; void read(Score); void printQuizAverages(Score); void printClassAverages(Score); int main( ) { Score score; cout << "Enter " << NUM_QUIZZES << " scores for each student: \n"; read(score); cout << "The quize averages are: \n"; printQuizAverages(score); cout << "The class averages are: \n"; printClassAverages(score); } void read(Score score) { for (int s=0; s < NUM_STUDENTS; s++) { cout << "Student " << s << ": "; for (int q=0; q < NUM_QUIZZES; q++) cin >> score[s][q]; } } void printQuizAverages(Score score) { for (int s=0; s < NUM_STUDENTS; s++) { float sum = 0.0; for (int q=0; q < NUM_QUIZZES; q++) sum += score[s][q]; cout << "\tStudent " << s << ": " << sum/NUM_QUIZZES << endl; } } void printClassAverages(Score score) { for (int q=0; q < NUM_QUIZZES; q++) { float sum = 0.0; for (int s=0; s < NUM_STUDENTS; s++) sum += score[s][q]; cout << "\tQuiz " << q << ": " << sum/NUM_STUDENTS << endl; } }
ทดสอบโปรแกรม เมื่อป้อนค่า (8, 7, 9, 8, 9), (9, 9, 9, 9, 8) และ (5, 6, 7, 8, 9) ตามลำดับ
Enter 5 scores for each student: Student 0: 8 7 9 8 9 Student 1: 9 9 9 9 8 Student 2: 5 6 7 8 9 The quize averages are: Student 0: 8.2 Student 1: 8.8 Student 2: 7 The class averages are: Quiz 0: 7.33333 Quiz 1: 7.33333 Quiz 2: 8.33333 Quiz 3: 8.33333 Quiz 4: 8.66667
ฟังก์ชัน printQuizAverage ( ) จะคำนวณและพิมพ์ค่าเฉลี่ยของคะแนนในแต่ละแถว ในขณะที่ ฟังก์ชัน printClassAverage ( ) จะคำนวณและพิมพ์ค่าเฉลี่ยของคะแนนในแต่ละสดมภ์
ตัวอย่าง 6.21 การประมวลผลแถวลำดับสามมิติ
int numZeros(int a[][4][3], int n1, int n2, int n3); int main() { int a[2][4][3] = { { {5,0,2}, {0,0,9}, {4,1,0}, {7,7,7} }, { {3,0,0}, {8,5,0}, {0,0,0}, {2,0,9} }}; cout << "This array has " << numZeros(a,2,4,3) << " zeros: \n"; } int numZeros(int a[][4][3], int n1, int n2, int n3) { int count =0; for (int i=0; i < n1; i++) for (int j=0; j < n2; j++) for (int k=0; k < n3; k++) if (a[i][j][k] == 0) ++count; return count; }
ทดสอบโปรแกรม
This array has 11 zeros:
ให้สังเกตุว่า การกำหนดค่าเริ่มต้นให้กับแถวลำดับสามมิติ เป็นการกำหนดค่าให้กับข้อมูล 2 กลุ่ม แต่ละกลุ่มมีข้อมูล 4 กลุ่มย่อย ที่แต่ละกลุ่มย่อยมีสมาชิก 3 ตัว รวมจำนวนสมาชิกทั้งสิ้น 24 ตัว ผู้เขียนโปรแกรมอาจกำหนดค่าเริ่มต้นของแถวลำดับ a ในตัวอย่างใหม่ ได้ดังนี้
int a[2][4][3] = { 5, 0, 2, 0, 0, 9, 4, 1, 0, 7, 7, 7, 3, 0, 0, 8, 5, 0, 0, 0, 0, 2, 0, 9}; int a[2][4][3] = { { 5,0,2, 0,0,9, 4,1,0, 7,7,7 }, { 3,0,0, 8,5,0, 0,0,0, 2,0,9 } };
อย่างไรก็ดี การกำหนดค่าในโปรแกรมตัวอย่าง จะทำให้ผู้อ่านโปรแกรมสามารถเข้าใจการกำหนดค่าได้ง่ายและรวดเร็วขึ้น