ต้นไม้ B กับต้นไม้ B + แตกต่างกันอย่างไร


293

ในขต้นไม้คุณสามารถจัดเก็บทั้งกุญแจและข้อมูลในโหนดภายในและใบแต่ในต้นไม้ B +คุณมีการจัดเก็บข้อมูลในที่โหนดใบเท่านั้น

มีข้อได้เปรียบอะไรบ้างจากการทำข้างต้นในต้นไม้ b +?

ทำไมไม่ใช้ b-trees แทน b + trees ทุกที่เพราะพวกเขาดูเหมือนว่าเร็วขึ้น?

ฉันหมายความว่าทำไมคุณต้องทำซ้ำคีย์ (data) ในต้นไม้ b +


37
ฉันคิดว่าสิ่งที่พวกเขาพูดคือ "B-Tree" กับ B + -Tree พวกเขาหมายถึงเครื่องหมายขีดกลางไม่ใช่เครื่องหมายลบ
STU

คำตอบ:


421

ภาพด้านล่างช่วยแสดงความแตกต่างระหว่างต้นไม้ B + และต้นไม้ B

ข้อดีของต้นไม้ B +:

  • เนื่องจากต้นไม้ B + ไม่มีข้อมูลที่เชื่อมโยงกับโหนดภายในปุ่มจึงสามารถมีปุ่มได้มากขึ้นบนหน้าหน่วยความจำ ดังนั้นจึงต้องใช้แคชที่น้อยลงเพื่อเข้าถึงข้อมูลที่อยู่ในโหนดลีฟ
  • โหนดใบไม้ของต้นไม้ B + นั้นเชื่อมโยงกันดังนั้นการสแกนวัตถุทั้งหมดในต้นไม้อย่างสมบูรณ์จึงต้องผ่านเชิงเส้นเดียวผ่านโหนดใบไม้ทั้งหมด ในทางกลับกันต้นไม้ AB นั้นจะต้องมีการแวะผ่านทุกระดับในต้นไม้ การข้ามผ่านต้นไม้เต็มรูปแบบนี้มีแนวโน้มที่จะมีการคิดถึงแคชมากกว่าการข้ามผ่านเชิงเส้นของ B + ทิ้ง

ข้อได้เปรียบของต้นไม้ B:

  • เนื่องจากทรี B มีข้อมูลพร้อมกับแต่ละคีย์โหนดที่เข้าถึงบ่อยจึงสามารถอยู่ใกล้กับรูทได้มากขึ้นและสามารถเข้าถึงได้รวดเร็ว

ต้นไม้ B และ B +


2
ข้อ จำกัด เกี่ยวกับจำนวนรายการใน leaf node หรือไม่?
TLE

38
@TLE เป็นคำถามที่ดี! ใช่. ฮาร์ดไดรฟ์เข้าถึงหน้าหน่วยความจำขั้นต่ำในแต่ละครั้งดังนั้นเราจึงต้องการให้พอดีกับพอยน์เตอร์ทั้งหมดในหน่วยความจำหน้าเดียว เราต้องการเพียงหนึ่งดิสก์อ่านต่อการเข้าถึงใบไม้ดังนั้นเราจึงไม่ต้องการที่จะกำหนดมากกว่าขนาดหน้าของตัวชี้ไปยังใบไม้ ถ้าเราเติมใบไม้ด้วยขนาดหน้าพอยน์เตอร์แล้วเราต้องการเพิ่มอีกหนึ่งพอยเตอร์ให้กับใบไม้นี้เราจะสร้างลูกสองคนของโหนดนี้และให้ครึ่งหนึ่งของพอยเตอร์ของใบไม้แก่เด็กใหม่แต่ละคน แน่นอนว่าอาจมีการปรับรูปทรงใหม่บางอย่างเพื่อให้แน่ใจว่าระดับความสูงของต้นไม้น้อยที่สุด สิ่งนี้ช่วยได้ไหม?
Rose Perrone

ตัวชี้สุดท้ายของโหนดใบไม้แต่ละใบของ B-tree ควรชี้ไปที่โหนดใบไม้ถัดไปใช่ไหม
camino

8
ขออภัยที่กระแทกหัวข้อเก่า แต่ความเห็นของ @ Babyburger เกี่ยวกับความคิดเห็นของคามิโนว่าถูกต้องจริงหรือไม่ ในความเป็นจริง B-Tree ไม่ได้เชื่อมต่อกับโหนดใบไม้ A B + แน่นอน
Jason

ขอบคุณสำหรับคำตอบที่ยอดเยี่ยมกรณีการใช้งานเมื่อต้องการสแกนวัตถุแบบเต็มในต้นไม้ B / B + ในบริบทฐานข้อมูลคืออะไร เนื่องจากส่วนใหญ่จะใช้สำหรับการจัดทำดัชนีการค้นหาแทบจะไม่เคยต้องสแกนต้นไม้ทั้งหมดและแทนที่จะสำรวจผ่านเส้นทางดัชนีนั้นถูกต้องหรือไม่
Siddhartha

113

ข้อได้เปรียบที่สำคัญของต้นไม้ B + เหนือต้นไม้ B คือช่วยให้คุณสามารถบรรจุพอยน์เตอร์ไปยังโหนดอื่นได้มากขึ้นโดยการลบพอยน์เตอร์ไปยังข้อมูลซึ่งจะเป็นการเพิ่ม fanout และลดความลึกของต้นไม้

ข้อเสียคือไม่มีลึกหนาบางต้นเมื่อคุณอาจพบการแข่งขันในโหนดภายใน แต่เนื่องจากโครงสร้างข้อมูลทั้งคู่มี fanouts ขนาดใหญ่การจับคู่ส่วนใหญ่ของคุณจะอยู่บนโหนดใบไม้ต่อไปทำให้ค่าเฉลี่ยของต้นไม้ B + มีประสิทธิภาพมากขึ้น


1
ฉันชอบคำตอบของ Jeff เพราะเน้นความแตกต่างของประสิทธิภาพเมื่อทำการสแกนแบบเต็ม
Rose Perrone

ฉันสับสนมากเพราะการสำรวจทรี b โดยใช้การสำรวจเส้นทางตามลำดับจะอ่านค่าทั้งหมดตามลำดับที่เรียงลำดับในเวลา O (n) หากแต่ละโหนดต้นไม้มีขนาดที่เหมาะสมสำหรับขนาดหน้ากระดาษจริงดูเหมือนว่าสิ่งต่าง ๆ จะไม่ได้รับสิ่งที่ดีที่สุดอีกต่อไป ในทางกลับกันค่าใช้จ่ายที่จะได้รับมูลค่าแรก (น้อยที่สุด) ใน b + tree คือ O (log n) และจากนั้นให้เดินผ่านใบไม้ทุกใบคือ O (n) ดังนั้นค่าใช้จ่ายทั้งหมดคือ O (log n + n) นี่คือการทำงานที่มากขึ้นและการอ่านดิสก์เพิ่มเติมซึ่งเหมาะสมเนื่องจากทรีมีข้อมูลพิเศษทั้งหมดอยู่ในนั้น ฉันไม่เข้าใจ
เอริค

มันจะเป็นอีกคำสำหรับ 'fanout' ในประโยคข้างต้น?
Jorge Bucaran

3
@JorgeBucaran fanout = จำนวนของขอบที่ออกมาจากโหนด
bantmen

33

B + Trees นั้นง่ายกว่าและมีประสิทธิภาพสูงกว่าในการสแกนแบบเต็มเช่นเดียวกับการดูข้อมูลทุกชิ้นที่ดัชนีต้นไม้เนื่องจากโหนดเทอร์มินัลสร้างรายการที่เชื่อมโยง ในการทำการสแกนแบบเต็มด้วย B-Tree คุณจะต้องทำการสำรวจแบบเต็มเพื่อหาข้อมูลทั้งหมด

ในทางกลับกัน B-Trees นั้นสามารถทำงานได้เร็วขึ้นเมื่อคุณทำการค้นหา (มองหาชิ้นส่วนของข้อมูลโดยใช้กุญแจ) โดยเฉพาะอย่างยิ่งเมื่อ Tree นั้นอยู่ใน RAM หรือที่เก็บข้อมูลอื่นที่ไม่ใช่บล็อก เนื่องจากคุณสามารถยกระดับโหนดที่ใช้กันทั่วไปในทรีได้จึงจำเป็นต้องทำการเปรียบเทียบข้อมูลน้อยลงเพื่อรับข้อมูล


1
คุณจะเห็นด้วยหรือไม่นั้นต้นไม้ B + จะถูกใช้สำหรับสถานการณ์ที่อาจมีลำดับการอ่านในข้อมูลทั้งหมดจึงสามารถข้ามใบไม้ได้ ในขณะที่ต้นไม้ B จะเหมาะสำหรับสถานการณ์การเข้าถึงแบบสุ่ม?
JDPeckham

31
  1. ในคีย์การค้นหาต้นไม้ B และข้อมูลจะถูกเก็บไว้ในโหนดภายในหรือโหนดใบไม้ แต่ใน B + -tree data จะถูกเก็บไว้ใน leaf nodes เท่านั้น
  2. การสแกนแบบเต็มของต้นไม้ B + นั้นง่ายมากเพราะข้อมูลทั้งหมดถูกค้นพบในโหนดใบไม้ การสแกนแบบเต็มของทรี B ต้องใช้การแวะผ่าน
  3. ในทรี B ข้อมูลอาจพบได้ในโหนดใบไม้หรือโหนดภายใน การลบโหนดภายในนั้นซับซ้อนมาก ในต้นไม้ B + ข้อมูลจะพบได้ในโหนดใบไม้ การลบโหนดใบไม้นั้นง่าย
  4. การแทรกในทรี B นั้นซับซ้อนกว่าทรี B +
  5. B + trees จัดเก็บคีย์ค้นหาที่ซ้ำซ้อน แต่ทรี B ไม่มีค่าซ้ำซ้อน
  6. ในต้นไม้ B + ข้อมูลใบโหนดจะถูกจัดเรียงเป็นรายการเชื่อมโยงตามลำดับ แต่ในต้นไม้ B โหนดใบไม่สามารถจัดเก็บได้โดยใช้รายการที่เชื่อมโยง การใช้งานระบบฐานข้อมูลจำนวนมากต้องการความเรียบง่ายเชิงโครงสร้างของต้นไม้ B +

15

ตัวอย่างจากแนวคิดระบบฐานข้อมูลที่ 5

B + -tree ต้นไม้ B +

B-tree ที่สอดคล้องกัน bTree


5
ฉันไม่คิดว่า B-Tree มีลิงค์ไปยังโหนดลูก ยกตัวอย่างเช่นรูปแบบไปClearview bucket Mianus Bucketมันจะไม่สมเหตุสมผลเลยที่จะทำเช่นนั้นเพราะในระหว่างสองสิ่งนั้นคุณมีสิ่งDowntown bucketที่ค้นหาได้มากในกรณีที่คุณต้องการทำการสแกนดัชนีในต้นไม้ B (ต้องมีการย้อนรอย) คุณได้สิ่งนี้มาจากไหน
Evan Carroll

1
@EvanCarroll แนวคิดระบบฐานข้อมูลอันดับที่ 5 บางทีคุณต้องยืนยันกับผู้เขียน :)
camino

11

กำหนด "เร็วกว่ามาก" Asymptotically พวกเขาเกี่ยวกับเดียวกัน ความแตกต่างอยู่ที่วิธีการใช้งานของที่เก็บข้อมูลสำรอง บทความ Wikipedia บนB-treesและB + treesดูน่าเชื่อถือ


2
ฉันเห็นด้วยกับชาร์ลี เนื่องจากหนึ่งโหนดของ B-Tree หมายถึงหนึ่งหน้าหน่วยความจำรองหรือบล็อกการส่งผ่านจากโหนดหนึ่งไปยังอีกโหนดหนึ่งต้องใช้เวลาในการเปลี่ยนหน้ามาก

11

Adegoke A, Amit

ฉันเดาว่าจุดสำคัญหนึ่งที่คุณคนหายไปคือความแตกต่างระหว่างข้อมูลและตัวชี้ตามที่อธิบายไว้ในส่วนนี้

Pointer: ตัวชี้ไปยังโหนดอื่น

ข้อมูล: - ในบริบทของดัชนีฐานข้อมูลข้อมูลเป็นเพียงตัวชี้ไปยังข้อมูลจริง (แถว) ซึ่งอยู่ในที่อื่น

ดังนั้นในกรณีที่ต้นไม้ B แต่ละโหนดมีคีย์ข้อมูลสามตัวชี้ไปยังข้อมูลที่เกี่ยวข้องกับคีย์และตัวชี้ไปยังโหนดลูก

ใน B + tree โหนดภายในเก็บคีย์และตัวชี้ไปยังโหนดชายน์ในขณะที่โหนดโหนดเก็บคีย์และตัวชี้ไปยังข้อมูลที่เกี่ยวข้อง สิ่งนี้อนุญาตให้มีจำนวนคีย์เพิ่มเติมสำหรับขนาดของโหนดที่กำหนด ขนาดของโหนดขึ้นอยู่กับขนาดบล็อกเป็นหลัก

ข้อดีของการมีคีย์ต่อโหนดอธิบายไว้ข้างต้นได้ดีดังนั้นฉันจะบันทึกความพยายามในการพิมพ์ของฉัน


10

B + Trees มีประโยชน์อย่างมากในการจัดเก็บแบบบล็อก (เช่นฮาร์ดดิสก์) ด้วยสิ่งนี้ในใจคุณจะได้รับประโยชน์หลายประการเช่น (จากส่วนบนของหัว):

  • fanout สูง / ความลึกต่ำ: นั่นหมายความว่าคุณต้องบล็อกน้อยลงเพื่อรับข้อมูล เมื่อข้อมูลถูกรวมเข้ากับพอยน์เตอร์การอ่านแต่ละครั้งจะได้รับพอยน์เตอร์น้อยลงดังนั้นคุณจึงต้องการการค้นหามากขึ้นเพื่อเข้าถึงข้อมูล

  • ที่เก็บข้อมูลบล็อกที่เรียบง่ายและสอดคล้องกัน: โหนดด้านในมีตัวชี้ N ไม่มีอะไรอีกโหนดโหนดมีข้อมูลไม่มีอะไรอื่น ที่ทำให้แยกวิเคราะห์แก้ปัญหาและสร้างใหม่ได้ง่าย

  • ความหนาแน่นของคีย์สูงหมายถึงโหนดบนเกือบจะแน่นอนในแคชในหลาย ๆ กรณีโหนดภายในทั้งหมดได้รับแคชอย่างรวดเร็วดังนั้นการเข้าถึงข้อมูลจึงต้องไปที่ดิสก์


2
ส่วนใหญ่สำหรับต้นไม้ในหน่วยความจำ; แต่มีตัวเลือกยอดนิยมอื่น ๆ เช่นต้นไม้สีแดงดำข้ามรายการและอื่น ๆ
Javier

B-trees ได้รับการออกแบบมาเพื่อการจัดเก็บแบบบล็อกที่มีประสิทธิภาพซึ่ง จำกัด จำนวนการเข้าถึงโหนดแบบไม่แสดงอาการ ไม่เช่นนั้นหากใช้สื่อบันทึกข้อมูลแบบหน่วยความจำที่มีการเข้าถึงแบบสุ่มเราสามารถใช้ต้นไม้ไบนารีแบบปรับสมดุลตนเองได้เช่นต้นไม้สีแดงดำเพื่อให้ได้ผลลัพธ์ที่ดีขึ้น
dionyziz

จุดแรกของคุณไม่ควรพูดว่า "พยายามน้อยลง" มากกว่า "ค้นหามากกว่า" ความลึกที่น้อยกว่า -> พยายามน้อยกว่า
Jesse

1
@Jesse: fanout สูง => ความลึกต่ำ => น้อยพยายาม แต่ข้อมูลและตัวชี้ผสมน้อยหมายถึงตัวชี้ => fanout ต่ำ => = ความลึกมากขึ้นพยายาม> อื่น ๆ
ฮาเวียร์

1
@AdegokeA: ต้นไม้ B + มีโหนดสองชนิด: โหนดภายในที่มีเฉพาะคีย์และพอยน์เตอร์เท่านั้นไม่มีข้อมูล และโหนดใบไม้ที่มีข้อมูลและไม่มีตัวชี้ ที่อนุญาตให้มีจำนวนคีย์สูงสุดในแต่ละโหนดภายใน ถ้าคุณเก็บข้อมูลไว้ในโหนดด้านในคุณก็จะสามารถพอยน์เตอร์น้อยลงและต้นไม้ของคุณจะสูงขึ้น
Javier

5

ใน B + Tree เนื่องจากมีเพียงพอยน์เตอร์จะถูกเก็บไว้ในโหนดภายในขนาดของมันจะเล็กกว่าโหนดภายในของ B tree (ซึ่งเก็บทั้ง data + key) ดังนั้นดัชนีของต้นไม้ B + สามารถดึงมาจากที่จัดเก็บข้อมูลภายนอกในการอ่านดิสก์เดียวซึ่งถูกประมวลผลเพื่อค้นหาตำแหน่งของเป้าหมาย หากเป็นทรี B ต้องมีการอ่านดิสก์สำหรับกระบวนการตัดสินใจแต่ละครั้งและทุกครั้ง หวังว่าฉันจะทำให้จุดที่ชัดเจน! :)


4

**

ข้อเสียเปรียบที่สำคัญของ B-Tree คือความยากของการข้ามผ่านคีย์ตามลำดับ B + Tree ยังคงคุณสมบัติการเข้าถึงแบบสุ่มอย่างรวดเร็วของ B-Tree ในขณะที่ยังอนุญาตการเข้าถึงอย่างรวดเร็วตามลำดับ

** อ้างอิง: โครงสร้างข้อมูลโดยใช้ C // ผู้แต่ง: Aaro M Tenenbaum

http://books.google.co.in/books?id=X0Cd1Pr2W0gC&pg=PA456&lpg=PA456&dq=drawback+of+B-Tree+is+the+difficulty+of+Traversing+the+keys+sequentially&source=bl&ots=pGcPQSEJMS&sig= F9MY7zEXYAMVKl_Sg4W-0LTRor8 & hl = th & SA = X & EI = nD5AUbeeH4zwrQe12oCYAQ และโดยผู้ดูแลระบบ = 0CDsQ6AEwAg # v = onepage & q = อุปสรรค% 20of% 20B ต้นไม้% 20is% 20the% 20difficulty% 20of% 20Traversing% 20the% 20keys% 20sequentially & F = false


1
นี่ควรเป็นคำตอบที่ถูกต้อง กล่าวโดยย่อ: สถานที่อ้างอิง
Theodore Zographos

2

ยกตัวอย่างหนึ่ง - คุณมีตารางที่มีข้อมูลจำนวนมากต่อแถว นั่นหมายความว่าทุกตัวอย่างของวัตถุมีขนาดใหญ่

หากคุณใช้ทรี B ที่นี่การใช้เวลาส่วนใหญ่จะสแกนหน้าเว็บที่มีข้อมูลซึ่งไม่มีประโยชน์ ในฐานข้อมูลที่เป็นสาเหตุของการใช้ B + Trees เพื่อหลีกเลี่ยงการสแกนข้อมูลวัตถุ

B + ต้นไม้แยกคีย์จากข้อมูล

แต่ถ้าขนาดข้อมูลของคุณน้อยกว่าคุณก็สามารถจัดเก็บไว้พร้อมกับกุญแจซึ่งเป็นสิ่งที่ต้นไม้ B ทำ


1
"ถ้าคุณใช้ทรี B ตรงนี้เวลาส่วนใหญ่จะสแกนหน้าเว็บที่มีข้อมูล" - ไม่จำเป็น โหนด B-tree สามารถเก็บ "พอยน์เตอร์" ไว้ในข้อมูลบนแผ่นดิสก์ได้เท่านั้น
TT_

2

ความแตกต่างหลักระหว่าง B-tree และ B + tree คือ B-tree กำจัดที่เก็บข้อมูลซ้ำซ้อนของค่าคีย์การค้นหาเนื่องจากคีย์การค้นหาไม่ซ้ำใน B-tree เราอาจไม่สามารถเก็บดัชนีโดยใช้โหนดต้นไม้น้อยลง กว่าในดัชนีต้นไม้ B + ที่เกี่ยวข้องอย่างไรก็ตามเนื่องจากคีย์การค้นหาที่ปรากฏในโหนดที่ไม่ใช่ใบปรากฏขึ้นที่อื่นใน B-tree เราจึงถูกบังคับให้รวมฟิลด์ตัวชี้เพิ่มเติมสำหรับแต่ละคีย์การค้นหาในโหนดที่ไม่ใช่ใบ ข้อดีคือพื้นที่ว่างสำหรับต้นไม้ B เนื่องจากการทำซ้ำไม่เกิดขึ้นและสามารถใช้กับดัชนีขนาดใหญ่ได้


1
น่าสนใจความคิดเกี่ยวกับการทำซ้ำนั้นไม่เหมือนใครในคำตอบที่นี่และทำให้เข้าใจได้ดีกว่าการสำรวจเส้นทางตามลำดับของต้นไม้ b + ที่มีประสิทธิภาพมากกว่าการสำรวจเส้นทางตามลำดับของต้นไม้ b-tree เท่าที่ฉันสามารถบอกได้ว่ามันไม่ถูกต้องหรือไม่ใช่เรื่องราวทั้งหมดตามลำดับการสำรวจเส้นทางของ b-tree คือ O (n) และการค้นหาโหนดที่เล็กที่สุดใน b + tree คือ O (log n) จากนั้น ภายในแต่ละใบคือ O (n) นอกเหนือจากนั้น อย่างไรก็ตามหากคุณกำลังจัดทำดัชนีบางสิ่งด้วยค่าเล็ก ๆ เช่นฟิลด์บูลีนต้นไม้ b + จะสมเหตุสมผลมากกว่าต้นไม้ b เนื่องจากการจัดการซ้ำ
Eric

1

ต้นไม้ B + เป็นต้นไม้ที่มีความสมดุลซึ่งทุกเส้นทางจากรากของต้นไม้ไปยังใบไม้นั้นมีความยาวเท่ากันและโหนดที่ไม่ใช่ใบของต้นไม้แต่ละต้นจะอยู่ระหว่าง [n / 2] และ [n] ลูกโดยที่ n คือ แก้ไขสำหรับต้นไม้โดยเฉพาะ มันมีหน้าดัชนีและหน้าข้อมูล ต้นไม้ไบนารีมีสองลูกต่อโหนดแม่เท่านั้นต้นไม้ B + สามารถมีจำนวนตัวแปรของลูกสำหรับแต่ละโหนดแม่


1
เพื่อความชัดเจนต้นไม้ B ไม่ใช่ต้นไม้ไบนารี ในความเป็นจริงต้นไม้ B และต้นไม้ B + อยู่ใกล้กันในการก่อสร้างและการใช้งานมากกว่าต้นไม้ไบนารี บทความ wiki สามารถช่วยในการล้างคำจำกัดความ - B + Tree , B TreeและBinary Tree
uutsav

1

การใช้ B + ต้นไม้ที่เป็นไปได้อย่างหนึ่งคือมันเหมาะสำหรับสถานการณ์ที่ต้นไม้มีขนาดใหญ่จนไม่เหมาะกับหน่วยความจำที่มีอยู่ ดังนั้นโดยทั่วไปคุณคาดหวังว่าจะทำหลาย I / O ของ
มันมักจะเกิดขึ้นที่ต้นไม้ B + ถูกนำมาใช้แม้ว่าในความเป็นจริงจะพอดีกับหน่วยความจำแล้วผู้จัดการแคชของคุณอาจเก็บไว้ที่นั่นอย่างถาวร แต่นี่เป็นกรณีพิเศษไม่ใช่แบบทั่วไปและนโยบายการแคชแยกจากการบำรุงรักษาต้นไม้ B + เช่นนี้

นอกจากนี้ในแผนภูมิ B + หน้าใบไม้จะถูกเชื่อมโยงเข้าด้วยกันในรายการที่เชื่อมโยง (หรือรายการที่เชื่อมโยงเป็นสองเท่า) ซึ่งเพิ่มประสิทธิภาพการสำรวจเส้นทาง (สำหรับการค้นหาช่วงการเรียงลำดับ ฯลฯ ) ดังนั้นจำนวนพอยน์เตอร์จึงเป็นฟังก์ชันของอัลกอริทึมเฉพาะที่ใช้


นี้อยู่ในคำตอบของคำถามที่ว่าทำไมเราไม่ควรใช้ B-ต้นไม้แทน B + ต้นไม้ทุก :)
สแต็คโปรแกรมเมอร์

3
แต่คุณอธิบายเพียงด้านเดียวเท่าที่เรารู้ด้วยคำตอบของคุณ b-trees สามารถทำงานในลักษณะเดียวกัน OP ขอให้อธิบายความแตกต่างและคุณพูดคุยเกี่ยวกับสิ่งหนึ่งเท่านั้นไม่ใช่สิ่งอื่น คุณไม่มีไดอะแกรมเวนน์ที่มีหนึ่งวงกลม!
Malfist
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.