คนคอมพิวเตอร์

Archive for ธันวาคม 2008

 

หน้าแรก สารบัญ เกี่ยวกับบล็อกนี้ เกี่ยวกับผู้เขียน

สร้างสแตกด้วยลิงค์ลิสต์ใน C#
สร้างสแตกที่เพิ่ม-ลดขนาดได้อย่างมีพลวัตสไตล์เมนเนจโค้ด

  • วันจันทร์ที่ 24 กันยายน พ.ศ. 2550
  • ลาภลอย วานิชอังกูร (laploy.com)

 

ในตอนที่แล้วผู้เขียนนำเสนอหลักการทำงาน และวิธีนิยามคลาสลิงค์ลิสต์ และสองตอนก่อนหน้านั้น นำเสนอวิธีสร้างสแตกจากอาร์เรย์ ในบทความตอนนี้ เราจะนำความรู้ทั้งสองมาบูรณาการด้วยการสร้างสแตกจากลิงค์ลิสต์ เพื่อศึกษาอัลกอริทึม และการทำงานภายในของโครงสร้างข้อมูล

 

โครงสร้างข้อมูลแบบสแตก

ท่านคงยังจำได้จากบทความที่ผ่านมาว่าโครงสร้างข้อมูลสแตก (stack หรือกองซ้อน) มีหลักการทำงานแบบ “เข้าล่าสุดได้ออกก่อน” (List in – First out หรือ LIFO) ยกตัวอย่างเช่น เมื่อเราพับเสื้อผ้าแล้ววางซ้อนไว้เป็นตั้ง เมื่อต้องการหยิบผ้ามาใส่ เราต้องหยิบชิ้นที่อยู่บนสุดก่อน วันรุ่งขึ้นจึงหยิบผ้าตัวถัดไป ไล่ไปเช่นนี้จนถึงตัวล่างสุด เราจะไม่หยิบผ้าตัวที่อยู่กลางๆ หรือล่างสุดออกมาก่อน เมื่อจะนำผ้าไปใส่ในตั้ง เราต้องใส่ไว้บนสุดของตั้ง เราจะไม่นำไปแทรกไว้ตรงกลางหรือล่างสุด

สแตกก็มีหลักการทำงานเช่นเดียวกันนี้ เมื่อเรานำข้อมูลใหม่ใส่ในสแตก ข้อมูลจะอยู่ที่ตำแหน่งบนสุดของสแตก (stack top) เมื่อต้องการดึงข้อมูลออก เราจะดึงได้เฉพาะตัวบนสุด (ตัวที่ใส่เข้าไปล่าสุด) เท่านั้น การใส่ข้อมูลในสแตกเรียกว่า push การนำข้อมูลออกเรียกว่า pop

สแตกที่สร้างจากอาร์เรย์ (array) จะมีสภาพเรียงเป็นแนวตั้ง เหมือนตั้งผ้าหรือจานที่เรียงซ้อนกัน ส่วนสแตกที่สร้างจากลิงค์ลิสต์จะมีลักษณะเป็นแนวนอน ต่อแถวกันเหมือนขบวนรถไฟ

 

สแตกที่สร้างจากอาร์เรย์มีเรียงเป็นแนวตั้ง

 

 
สแตกที่สร้างจากลิงค์ลิสต์มีลักษณะเป็นแนวนอน

 

 

โหนดและลิงค์ลิสต์

ท่านคงยังจำได้ว่าลิงค์ลิสต์ (linked list หรือรายการเชื่อมโยง) ประกอบขึ้นจากองค์ประกอบพื้นฐานที่เรียกว่า “โหนด” (node) โหนดมีองค์ประกอบสามส่วนคือ ส่วนเก็บข้อมูล (data) ตัวอ้างอิงไปยังโหนดก่อนหน้า (previous) และตัวอ้างอิงไปยังโหนดถัดไป (next) ภายในลิงค์ลิสต์อาจมีโหนดเพียงโหนดเดียวหรือหลายล้านโหนดก็ได้ เรานิยามโหนดจากคลาสซึ่งมีโครงสร้าง (class outline) ดังนี้

โปรดสังเกตว่าตัวอ้างอิงทั้ง previous และ next เป็นออพเจ็กต์ เราไม่ใช้พอยน์เตอร์อย่างในภาษา C++ เพราะในบทความนี้เราจะเขียนโปรแกรมแบบเมนเนจโค้ด (managed code) เท่านั้น

 

 

โหนดมีองค์ประกอบสามส่วนคือ ส่วนเก็บข้อมูล (data) ตัวอ้างอิงไปยังโหนดก่อนหน้า (previous) และตัวอ้างอิงไปยังโหนดถัดไป (next)

 

คลาส LinkedList

ท่านคงยังจำได้ว่าในบทความตอนที่แล้วเรานิยามคลาสลิงค์ลิสต์ซึ่งมีสมาชิกเพียงห้าตัวคือ

  • front : ตัวอ้างอิงตำแหน่งหัวของลิงค์ลิสต์ ใช้อ้างถึงโหนดที่อยู่หน้าสุด
  • back : ตัวอ้างอิงตำแหน่งท้ายของลิงค์ลิสต์ ใช้อ้างถึงโหนดที่อยู่หลังสุด
  • LinkedList : เมธอดคอนสทรักเตอร์ ทำหน้าที่กำหนดค่าเริ่มต้นการทำงาน
  • AddpendNode : เมธอดทำหน้าที่เพิ่มโหนดใหม่เข้าไปต่อท้ายลิงค์ลิสต์
  • DisplayNodes : เมธอดทำหน้าที่แสดงข้อมูลทุกโหนดในลิงค์ลิสต์

โครงสร้างของคลาสแบบย่อ (class outline) เป็นดังนี้

 

 

สร้างสแตกจากลิงค์ลิสต์

สแตกที่สร้างจากอาร์เรย์มีข้อเสียคือต้องกำหนดขนาดไว้ตายตัว เพราะเมื่อเรากำหนดขนาด (ความลึก) ของอาร์เรย์ไปแล้วเราไม่สามารถเปลี่ยนแปลงภายหลังได้ ในตอนที่แล้วท่านได้เห็นแล้วว่า โครงสร้างแบบลิงค์ลิสต์มีพลวัต คือเพิ่มหรือลดขนาดได้ตามใจชอบ สแตกจะมีความยืดหยุ่นกว่าหากสร้างขึ้นจากลิงค์ลิสต์ ดังนั้นในบทความนี้เราจะนิยามคลาสชื่อ StackLinkedList เพื่อสร้างสแตกจากลิงค์ลิสต์

โปรดสังเกตว่าเรานิยามตัวกำหนดการเข้าถึง (access modifier) ของฟิลด์ front และ back ให้เป็นแบบ protected ทำให้คลาสที่สืบคุณสมบัติ (inherited) ไปจากคลาสนี้ (คลาสลูก) สามารถเข้าถึงฟิลด์ทั้งสองนี้ได้

 

การนำลิงค์ลิสต์มาใช้สร้างสแตกจะมีผลให้ส่วนล่างสุดของสแตก (stack bottom) อยู่ที่หัวของลิงค์ลิสต์ และยอดของสแตก (stack top) อยู่ที่ท้ายของลิงค์ลิสต์

 

 

คลาส StackLinkedList

เนื่องจากคลาส StackLinkedList มีการทำงานบางส่วนเหมือนคลาส LinkedList ที่เราเคยนิยามคลาสไว้แล้ว ดังนั้นเราจึงไม่จำเป็นต้องเขียนโค้ดใหม่ทั้งหมด เพราะเราสามารถใช้หลักการสืบคุณสมบัติ (inheritance) เพื่อต่อยอดได้ คลาส StackLinkedList มีสร้างของคลาสแบบย่อ (class outline) ดังนี้

คำสั่งบรรทัดที่ 7 จะเห็นว่าคลาสนี้ใช้คลาส LinkedList เป็นคลาสฐาน (base class) ทำให้มันได้รับมรดกมาทั้งหมด คลาส  StackLinkedList มีสมาชิกเพียงสามตัว ทั้งหมดเป็นเมธอดแบบ public บรรทัดที่ 9 เมธอด Push ทำหน้าที่เพิ่มข้อมูลใหม่เข้าสู่ตำแหน่งบนสุดของสแตก บรรทัดที่ 13 เมธอด Pop ทำหน้าที่ดึงข้อมูลตัวล่าสุดออกจากสแตก และสุดท้าย บรรทัดที่ 30 เมธอด IsEmpty ทำหน้าที่ตรวจสอบว่าสแตกว่างเปล่าหรือไม่

 

การเพิ่มข้อมูลเข้าสู่สแตก

ตอนที่เราสร้างสแตกด้วยอาร์เรย์ เมื่อเราต้องการ push ข้อมูลเข้าสู่สแตก เราใช้วิธีนำข้อมูลไปใส่ในตำแหน่งที่ยังว่างอยู่ในอาร์เรย์ แต่ตอนนี้เราจะใช้ลิงค์ลิสต์ เราจึงต้องนำข้อมูลใหม่ไปใส่ไว้ต่อท้ายลิงค์ลิสต์ สิ่งที่เราต้องทำคือสร้างเมธอดชื่อ Push เพื่อให้ทำหน้าที่นี้

การเพิ่มข้อมูลใหม่เข้าสู่ลิงค์ลิสต์คือการใส่โหนดใหม่นั่นเอง โชคดีที่เรานิยามเมธอดชื่อ AppendNode ซึ่งทำหน้าที่นี้ไว้เรียบร้อยแล้ว (ดูรายละเอียดในบทความตอนที่แล้ว) เมธอด Push จึงไม่มีโค้ดอะไรมาก แค่เรียกใช้เมธอด  AppendNode ก็พอ นิยามของเมธอด Push จึงมีเพียงเท่านี้

เนื่องจากเมธอด  AppendNode มีอาร์กิวเมนต์หนึ่งตัว (เป็นข้อมูลที่จะนำไปใส่ในโหนดใหม่) เราจึงต้องนิยามให้เมธอด Push มีพารามิเตอร์หนึ่งตัวเพื่อนำไปใช้เป็นค่าที่จะส่งให้แก่ เมธอด  AppendNode ด้วย

สาเหตุที่เราเรียกใช้เมธอด AppendNode ในคลาสนี้ได้ เพราะเรานิยามเมธอดนี้ไว้เป็นแบบ public ทำให้เรียกใช้ได้จากทุกที่ในโปรแกรม ท่านอาจสงสัยว่าในเมื่อเป็นเช่นนั้น ทำไมจึงไม่ให้โค้ดภายนอก (client class หมายถึงโค้ดที่นำจะคลาส StackLinkedList นี้ไปใช้)  เรียกใช้เมธอด AppendNode โดยตรง ทำไมจึงต้องนิยามเมธอด Push ขึ้นอีก

คำตอบคือเราไม่ต้องการให้ผู้ใช้ (หมายถึงผู้นำที่จะคลาสนี้ไปใช้สร้างสแตก) รู้รายละเอียดการทำงานภายในคลาส ผู้ใช้ไม่จำเป็นต้องรับรู้อะไรเกี่ยวกับโหนด เมื่อต้องการใส่ข้อมูลในสแตกก็เพียงแค่เรียกเมธอด Push ทำให้คลาสของเราใช้งานได้ง่ายขึ้น (ตามหลักการ information hiding)

 

การนำข้อมูลออกจากสแตก

เมธอด Pop ทำหน้าที่นำข้อมูลออกจากสแตก ในกรณีนี้คือนำข้อมูลออกจากโหนดที่อยู่ท้ายสุดของลิงค์ลิสต์ เมื่อนำข้อมูลออกมาแล้ว เราจำเป็นต้องนำโหนดนั้นออกจากลิงค์ลิสต์ด้วย โค้ดของเมธอด Pop เป็นดังนี้

เมธอด Pop อ่านมูลออกจากโหนดที่อยู่ท้ายสุดของลิงค์ลิสต์ แล้วลบโหนดนั้นออกจากลิงค์ลิสต์ เพื่อให้สแตกของเรามีสภาพการทำงานแบบ “เข้าล่าสุดได้ออกก่อน” คำสั่งบรรทัดที่ 15 เรียกเมธอด IsEmpty เพื่อตรวจสอบว่าลิงค์ลิสต์ว่างเปล่าหรือไม่ ผู้เขียนจะอธิบายการทำงานของเมธอด IsEmpty ในหัวข้อถัดไป ตอนนี้เพียงให้เข้าใจว่าเมธอด IsEmpty จะให้ค่าเป็น “จริง” (true) หากลิงค์ลิสต์ว่างเปล่า และให้ค่าเป็น “เท็จ” (false) หากลิงค์ลิสต์มีโหนดอยู่ภายใน

หากผู้ใช้เรียกเมธอด Pop ขณะที่สแตกไม่มีข้อมูล (ไม่มีโหนดอยู่ในลิงค์ลิสต์) เมธอด Pop จะจบการทำงานที่บรรทัด 15 และส่งค่า -1 กลับไปให้ผู้เรียก เพื่อเป็นเครื่องชี้ว่าสแตกว่าง

บรรทัดที่ 16 สร้างตัวแปรชื่อ retVal ทำหน้าที่เก็บค่าส่งกลับ (return value) แล้วอ่านข้อมูลจากโหนดหลังสุดของลิงค์ลิสต์ บรรทัดที่ 17 สร้างออพเจ็กต์ temp แล้วนำโหนดท้ายสุดของลิงค์ลิสต์มาเก็บไว้ ผู้เขียนใช้ temp เพื่ออธิบายการทำงานของโค้ด สมมุติว่าเรา Push ข้อมูลเข้าไปในสแตกแล้วสองหน หนแรกใส่ข้อมูลเป็น 15 หนที่สองใส่ข้อมูลเป็น 46 เราจะมีโหนดสองโหนด โค้ดบรรทัดที่ 4 จะทำให้ retVal มีค่าเป็น 46 และโค้ดบรรทัด 15 จะมีทำให้ temp มีค่าเท่ากับโหนด 2

 

สิ่งที่เกิดขึ้นเมื่อโค้ดบรรทัดที่ 4 และ 5 ในเมธอด Pop ทำงาน

 

บรรทัดที่ 18 คำสั่ง if ทำหน้าที่ตรวจสอบว่าภายในลิงค์ลิสต์มีโหนดเพียงโหนดเดียวหรือไม่ โดยดูที่พร็อพเพอร์ตี Previous ของโหนด back หากเป็น null แสดงว่าไม่มีโหนดก่อนหน้าโหนด back อีกแล้ว ซึ่งหมายความว่าโหนด back เป็นโหนดแรก (และเป็นโหนดสุดท้ายด้วย) ในลิงค์ลิสต์จึงมีเพียงโหนดเดียว

เมื่อคำสั่ง if ตรวจสอบแล้วพบว่ามีโหนดเดียว เราจะต้องทำให้ลิงค์ลิสต์ว่างเปล่า โปรแกรมจะทำงานบรรทัดที่ 20 และ 21 เพื่อเซตค่าให้ตัวเก็บค่าอ้างอิง back และ front มีค่าเป็น null เพื่อแสดงว่าลิงค์ลิสต์ว่างเปล่า หากคำสั่ง if ตรวจสอบแล้วพบว่ามีโหนดมากกว่าหนึ่งโหนด เราต้องลบโหนดนั้น การลบโหนดเราไม่จำเป็นต้องล้างค่าในหน่วยความจำ หรือลบค่าในตัวแปร เพียงแค่เปลี่ยนค่า back ก็พอ บรรทัด 25 กำหนดให้ Previous ชี้ไปยังโหนดก่อนหน้า บรรทัด 26 กำหนดให้ Next เป็น null (คือไม่ชี้ไปยังออพเจ็กต์ใดๆ) 

หากอ่านย่อหน้าบนแล้วงง ต้องไล่โค้ดจากการทำงานจริง เช่น เมื่อเรา Push ข้อมูลสองหน หนแรกใส่ข้อมูลเป็น 15 หนที่สองใส่ข้อมูลเป็น 46 เราจะมีโหนดสองโหนด โดยมี front เป็นโหนดแรก และ back เป็นโหนดที่ 2 คำสั่งบรรทัดที่ 13 ทำให้ back กลายเป็นโหนดที่ 1 คำสั่งบรรทัดที่ 26 ทำให้ค่า Next ของ back (โหนดที่ 1) กลายเป็น null (ดูรูป)

 

 
สิ่งที่เกิดขึ้นเมื่อโค้ดบรรทัดที่ 13 และ 14 ในเมธอด Pop ทำงาน

 

เมธอด IsEmpty

เมธอดนี้ทำหน้าที่ตรวจสอบว่าสแตกมีข้อมูลหรือไม่ ซึ่งทำได้โดยดูว่าในลิงค์ลิสต์มีโหนดหรือไม่ หากไม่มี แสดงว่าสแตกว่างเปล่า

 
การตรวจสอบทำได้โดยดูที่ตัวชี้ front หาก front มีค่าเป็น null (คือไม่ได้ชี้ไปที่โหนดใดเลย) แสดงว่าไม่มีโหนดอยู่ในลิงค์ลิสต์แล้ว หากเป็นเช่นนั้น บรรทัด 4 จะทำงาน โดยออกจากเมธอดพร้อมกับส่งค่าเป็นจริง หาก front ไม่เป็น null บรรทัด 5 จะทำงานโดยออกจากเมธอดพร้อมกับส่งค่าเป็นเท็จ

โค้ดโดยสมบูรณ์ของคลาส StackLinkedList เป็นดังนี้

 

โปรแกรมทดสอบ

เมื่อนิยามคลาส StackLinkedList เสร็จแล้ว ต่อไปเราต้องเขียนโค้ดเพื่อทดสอบการทำงาน

 

โค้ดที่เห็นข้างบนคือเมธอด Main ที่อยู่ในคลาส Program โค้ดบรรทัดที่ 3 สร้างตัวแปร myStack เพื่ออ้างอิงออพเจ็กต์สแตก โค้ดบรรทัดที่ 4 ถึง 6 เรียกเมธอด Push เพื่อนำข้อมูลไปใส่บนยอดของสแตก

 

สิ่งที่เกิดขึ้นเมื่อโค้ดบรรทัดที่ 4 ถึง 6 ในเมธอด Main ทำงาน

 

บรรทัดที่ 7 เรียกเมธอด DisplayNodes ที่นิยามไว้ในคลาส LinkedList (ดูรายละเอียดในบทความตอนที่แล้ว) เพื่อแสดงข้อมูลในโหนดทุกโหนดบนจอภาพ บรรทัดที่ 8 ถึง 11 เรียกเมธอด Pop เพื่อนำข้อมูลออกจากยอดของสแตกพร้อมกับแสดงข้อมูลนั้นบนจอภาพ

 

สิ่งที่เกิดขึ้นเมื่อโค้ดบรรทัดที่ 8 ในเมธอด Main ทำงาน

เมื่อรันโปรแกรม จะได้ผลลัพธ์ดังนี้

10
20
30
30
20
10
-1

 

แผนภูมิแสดงคลาส

ผู้เขียนสร้างโปรเจคด้วยโปรแกรม Microsoft Visual Studio .NET 2005 แล้วเขียนโค้ดทั้งหมดด้วยภาษา C# เวอร์ชัน 2.0 (ทำงานใน .NET Framework 2.0) เมื่อนิยามคลาสครบหมดแล้วใช้เครื่องมือสร้างแผนภูมิแสดงคลาส (class diagram) จะได้ผลลัพธ์ดังที่เห็นในภาพ

 

แผนภูมิแสดงคลาส (class diagram)

โปรดสังเกตว่าคลาส Node มีสมาชิกแบบฟิลด์ พร็อพเพอร์ตี และเมธอด ส่วนคลาส LinkedList มีสมาชิกแบบแบบฟิลด์ พร็อพเพอร์ตี ส่วนคลาส StackLinkedList มีเพียงสมาชิกแบบเมธอดเท่านั้น และคลาสStackLinkedList มีลูกศรโยงไปยังคลาส LinkedList เพื่อเป็นเครื่องแสดงว่า คลาส LinkedList เป็นคลาสฐาน

 

สรุปการสร้างสแตกจากลิงค์ลิสต์

การสร้างสแตกจากอาร์เรย์มีประสิทธิภาพกว่า เพราะเมื่อเราประกาศอาร์เรย์ CLR (Common Language Runtime ตัวรันไทมน์ของดอตเน็ต) จะจองหน่วยความจำเป็นพื้นที่ติดกันหมด จึงทำงานได้รวดเร็วกว่าลิงค์ลิสต์ ซึ่งเป็นออพเจ็กต์จำนวนมากที่กระจายอยู่ในฮีพ (heap)

ผู้เขียนนิยามคลาส StackLinkedList เพื่ออธิบายโครงสร้างข้อมูลเท่านั้น ในดอตเน็ตมีคลาส Stack (เนมสเปส Collections.Generic) เตรียมไว้ให้ใช้สร้างสแตกแล้ว เป็นสแตกที่ถูกสร้างจากอาร์เรย์ซึ่งเพิ่มลดขนาดได้ (CLR จะเปลี่ยนแปลงขนาดของอาร์เรย์ภายในให้โดยอัตโนมัติ) และมีข้อดีคือเป็นเจนเนอริก (generic) ทำให้ใช้ได้กับข้อมูลหลายชนิด (type)

ท่านสามารถดาวน์โหลดซอร์สโค้ดของบทความนี้ได้จากเว็บไซต์ laploy.com (เลือกหัวข้อดาวน์โหลด ไฟล์ชื่อ StackLinkedList.zip )หากท่านมีข้อสงสัยใดๆ โปรดใส่คำถามไว้ที่กระดานถาม-ตอบซึ่งอยู่ในเว็บไซต์เดียวกัน

 

Advertisements

เกี่ยวกับบล็อกนี้

เว็บบล็อก “คนคอมพิวเตอร์” หรือ Laploy’s articles เป็นบล็อกรวบรวมบทความจาก ลาภลอย วานิชอังกูร มีบทความหลายประเภทคละกัน เช่นบทความเกี่ยวกับการพัฒนาซอฟต์แวร์ บทความเกี่ยวกับการสร้างและดัดแปลงฮาร์ดแวร์ บทความเกี่ยวกับเทคโนโลยีคอมพิวเตอร์ทั่วไป บทความทั่วไป และนิยายนักสืบ

เกี่ยวกับผู้เขียน

ลาภลอย วานิชอังกูร เป็นผู้เชี่ยวชาญการพัฒนาแอพลิเกชันฐานข้อมูลและ Business Intelligence โดยเริ่มจากการพัฒนาโปรแกรมด้วย dBaseII, Clipper, FoxPro ปัจจุบันเป็นผู้เชี่ยวชาญในการบูรณาการระบบฐานข้อมูลด้วยเทคโนโลยีของไมโคร ซอฟต์เช่น ASP.NET, ADO.NET, Microsoft SQL Server 2008 และ LINQ ชำนาญการเขียนคิวรีเพื่อแก้ปัญหาทางธุรกิจที่ซับซ้อน Data mining, Data Warehouse, OLAP (SSRS), OLTP เคยออกแบบฐานข้อมูลสัมพันธ์ในองค์กรระหว่างประเทศ เคยพัฒนาแอพลิเกชันฐานข้อมูลในโครงการขนาดใหญ่หลายโครงการ และเคยให้คำปรึกษาด้าน BI ในศูนย์คอมพิวเตอร์ (T-Center) ในองค์กรของประเทศฝรั่งเศส
นอกจากงานฐานข้อมูลแล้ว ลาภลอย วานิชอังกูร ยังเชี่ยวชาญการพัฒนาซอฟต์แวร์ระบบฝังตัว (Microprocessor / Microcontroller Based Embedded System) งานพัฒนาแอพลิเกชันในอินเตอร์เน็ตแบบ RIA (Rich Internet Application) งานพัฒนาโครงสร้างพื้นฐานของซอฟต์แวร์ด้วยหลักการ OOP (Framework Development in Object Oriented Programming) ด้วยภาษา C# และ .NET Framework และงานบูรณาการระบบในองค์กรหรือ SOA (Service Oriented Architecture for Enterprise Orchestration) เคยร่วมงานกับทีมพัฒนาซอฟต์แวร์ในหลายๆ ประเทศ เช่น ไทย อินเดีย สวิส เยอรมัน และประเทศสหรัฐอเมริกา
ปัจจุบัน ลาภลอย วานิชอังกูร ทำหน้าที่ให้คำปรึกษาการวางระบบ IT (เช่น SQL, OLAP,.NET, SCADA, BI, SOA และอื่นๆ) ให้แก่หน่วยงานขนาดใหญ่หลายแห่ง และมีบทความทางวิชาการตีพิมพ์ในวารสารหลายเล่มอย่างสม่ำเสมอ และเป็นผู้เขียนหนังสือ "เรียนรู้ด้วยตนเอง DataBase - Query - T-SQL - Stored Procedure" และ “เรียนรู้ด้วยตนเอง OOP C# ASP.NET” (ISBN 13:978-974-212-598-1)
ท่านสามารถติดต่อผู้เขียนได้ที่อีเมล laploy@gmail.com

เรียนรู้ด้วยตนเอง OOP C# ASP.NET

ชื่อหนังสือ : เรียนรู้ด้วยตนเอง OOP C# ASP.NET โดย : ลาภลอย วานิชอังกูร จัดพิมพ์จัดจำหน่ายโดย : บริษัท ซีเอ็ดยูเคชั่น จำกัด (มหาชน) ISBN : 13:978-974-212-598-1 ราคา : 349 บาท จำนวนหน้า : 648 ขนาด : 19x29 ซ.ม.

เรียนรู้ด้วยตนเอง DataBase – Query – T-SQL – Stored Procedure

ชื่อหนังสือ: เรียนรู้ด้วยตนเอง DataBase - Query - T-SQL - Stored Procedure โดย: ลาภลอย วานิชอังกูร จัดพิมพ์จัดจำหน่าย: บริษัท ซีเอ็ดยูเคชั่น จำกัด (มหาชน) ISBN: 978-616-08-0009-4 ราคา: 559 บาท จำนวนหน้า: 1,100 ขนาด: 19x29 ซ.ม. วางตลาด: ตุลา 2552

กรุณาป้อนอีเมลของท่าน

Join 17 other followers

Advertisements