มันเป็นรายการที่เชื่อมโยงอาร์เรย์หรือไม่ ฉันค้นหาไปรอบ ๆ และพบเพียงคนที่คาดเดา ความรู้ C ของฉันไม่ดีพอที่จะดูซอร์สโค้ด
มันเป็นรายการที่เชื่อมโยงอาร์เรย์หรือไม่ ฉันค้นหาไปรอบ ๆ และพบเพียงคนที่คาดเดา ความรู้ C ของฉันไม่ดีพอที่จะดูซอร์สโค้ด
คำตอบ:
มันเป็นอาร์เรย์แบบไดนามิก ข้อพิสูจน์ในทางปฏิบัติ: การจัดทำดัชนีต้องใช้เวลา (แน่นอนว่ามีความแตกต่างน้อยมาก (0.0013 ecsecs!)) ในเวลาเดียวกันโดยไม่คำนึงถึงดัชนี:
...>python -m timeit --setup="x = [None]*1000" "x[500]"
10000000 loops, best of 3: 0.0579 usec per loop
...>python -m timeit --setup="x = [None]*1000" "x[0]"
10000000 loops, best of 3: 0.0566 usec per loop
ฉันจะประหลาดใจถ้า IronPython หรือ Jython ใช้รายการที่เชื่อมโยง - พวกเขาจะทำลายประสิทธิภาพของห้องสมุดที่ใช้กันอย่างแพร่หลายจำนวนมากที่สร้างขึ้นบนสมมติฐานที่ว่ารายการนั้นเป็นอาร์เรย์แบบไดนามิก
x=[None]*1000
โดยปล่อยให้การวัดความแตกต่างของการเข้าถึงรายการที่เป็นไปได้ค่อนข้างไม่แน่นอน คุณต้องแยกการกำหนดค่าเริ่มต้น:-s "x=[None]*100" "x[0]"
รหัส C นั้นค่อนข้างเรียบง่าย การขยายแมโครหนึ่งรายการและตัดการแสดงความคิดเห็นที่ไม่เกี่ยวข้องออกไปโครงสร้างพื้นฐานจะอยู่ในlistobject.h
ซึ่งจะกำหนดรายการเป็น:
typedef struct {
PyObject_HEAD
Py_ssize_t ob_size;
/* Vector of pointers to list elements. list[0] is ob_item[0], etc. */
PyObject **ob_item;
/* ob_item contains space for 'allocated' elements. The number
* currently in use is ob_size.
* Invariants:
* 0 <= ob_size <= allocated
* len(list) == ob_size
* ob_item == NULL implies ob_size == allocated == 0
*/
Py_ssize_t allocated;
} PyListObject;
PyObject_HEAD
มีจำนวนการอ้างอิงและตัวระบุชนิด มันเป็นเวกเตอร์ / อาร์เรย์ที่ overallocates listobject.c
รหัสสำหรับการปรับขนาดเช่นอาร์เรย์เมื่อมันเต็มอยู่ใน มันไม่ได้เพิ่มอาร์เรย์เป็นสองเท่า แต่เพิ่มขึ้นโดยการจัดสรร
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
new_allocated += newsize;
ต่อความจุในแต่ละครั้งที่newsize
มีขนาดที่ร้องขอ (ไม่จำเป็นต้องเป็นallocated + 1
เพราะคุณสามารถextend
ใช้องค์ประกอบตามจำนวนที่กำหนดแทนการใช้งานappend
ทีละชิ้น)
array
โมดูลหรือ NumPy จะเป็นที่ต้องการ
ใน CPython รายการคืออาร์เรย์ของพอยน์เตอร์ การใช้งานอื่น ๆ ของ Python อาจเลือกที่จะเก็บไว้ในรูปแบบที่แตกต่างกัน
นี่ขึ้นอยู่กับการใช้งาน แต่ IIRC:
ArrayList
ดังนั้นพวกเขาทั้งหมดมีการเข้าถึงแบบสุ่ม O (1)
O(1)
การทำดัชนีรายชื่อเป็นข้อสันนิษฐานที่ค่อนข้างธรรมดาและใช้ได้จริงไม่มีการใช้งานใดที่กล้าทำลาย
ผมจะแนะนำบทความ Laurent Luce ของ "งูใหญ่การดำเนินรายการ" มีประโยชน์จริง ๆ สำหรับฉันเพราะผู้เขียนอธิบายวิธีการนำรายการไปใช้ใน CPython และใช้ไดอะแกรมที่ยอดเยี่ยมสำหรับจุดประสงค์นี้
รายการโครงสร้าง C วัตถุ
วัตถุรายการใน CPython จะถูกแทนด้วยโครงสร้าง C ต่อไปนี้
ob_item
เป็นรายการของตัวชี้ไปยังองค์ประกอบรายการ จัดสรรคือจำนวนของสล็อตที่จัดสรรในหน่วยความจำtypedef struct { PyObject_VAR_HEAD PyObject **ob_item; Py_ssize_t allocated; } PyListObject;
สิ่งสำคัญคือต้องสังเกตความแตกต่างระหว่างสล็อตที่จัดสรรและขนาดของรายการ
len(l)
ขนาดของรายการเป็นเช่นเดียวกับ จำนวนของสล็อตที่จัดสรรคือสิ่งที่ถูกจัดสรรในหน่วยความจำ บ่อยครั้งที่คุณจะเห็นว่าการจัดสรรสามารถมากกว่าขนาด นี่คือการหลีกเลี่ยงการโทรrealloc
ทุกครั้งที่มีองค์ประกอบใหม่ถูกผนวกเข้ากับรายการ
...
ผนวก
l.append(1)
เราผนวกจำนวนเต็มเพื่อรายการนี้: เกิดอะไรขึ้น?
l.append(2)
เรายังคงได้โดยการเพิ่มองค์ประกอบหนึ่งเพิ่มเติมได้ที่:list_resize
ถูกเรียกด้วย n + 1 = 2 แต่เนื่องจากขนาดที่จัดสรรคือ 4 จึงไม่จำเป็นต้องจัดสรรหน่วยความจำเพิ่มเติม สิ่งเดียวกันเกิดขึ้นเมื่อเราเพิ่ม 2l.append(3)
จำนวนเต็มเพิ่มเติมได้ที่:l.append(4)
, แผนภาพต่อไปนี้แสดงสิ่งที่เรามีจนถึงตอนนี้
...
แทรก
ลองใส่จำนวนเต็มใหม่ (5) ที่ตำแหน่ง 1:
l.insert(1,5)
และดูสิ่งที่เกิดขึ้นภายใน
...
ป๊อปอัพ
เมื่อคุณป๊อปองค์ประกอบสุดท้าย:
l.pop()
,listpop()
เรียกว่าlist_resize
เรียกว่าข้างในlistpop()
และถ้าขนาดใหม่น้อยกว่าครึ่งหนึ่งของขนาดที่จัดสรรแล้วรายการจะหดตัวคุณสามารถสังเกตเห็นว่าช่อง 4 ยังชี้ไปที่จำนวนเต็ม แต่สิ่งสำคัญคือขนาดของรายการซึ่งตอนนี้ 4 ลองเพิ่มองค์ประกอบอีกหนึ่งรายการ ใน
list_resize()
ขนาด - 1 = 4 - 1 = 3 น้อยกว่าครึ่งหนึ่งของสล็อตที่จัดสรรดังนั้นรายการจะถูกย่อเป็น 6 สล็อตและขนาดใหม่ของรายการตอนนี้คือ 3คุณสามารถสังเกตได้ว่าช่อง 3 และ 4 ยังคงชี้ไปที่จำนวนเต็มบางส่วน แต่สิ่งสำคัญคือขนาดของรายการซึ่งตอนนี้เป็น 3
...
นำ
l.remove(5)
วัตถุของรายการงูใหญ่มีวิธีการในการลบองค์ประกอบที่เฉพาะเจาะจง:
aggregation
composition
ฉันหวังว่าจะมีรายการขององค์ประกอบเช่นกัน
อ้างอิงถึงเอกสาร ,
รายการของ Python เป็นอาร์เรย์ที่มีความยาวผันแปรได้จริงไม่ใช่รายการที่เชื่อมโยงแบบ Lisp
ดังที่คนอื่น ๆ ได้กล่าวไว้ข้างต้นรายการ (เมื่อมีขนาดใหญ่มาก) ถูกนำไปใช้โดยการจัดสรรพื้นที่จำนวนคงที่และถ้าพื้นที่นั้นควรเติมเติมเต็มจัดสรรพื้นที่จำนวนมากขึ้นและคัดลอกองค์ประกอบ
เพื่อให้เข้าใจว่าทำไมวิธีดังกล่าวจึงถูกตัดทอน O (1) โดยไม่สูญเสียความคิดทั่วไปเราได้ใส่องค์ประกอบ = 2 ^ n และตอนนี้เราต้องเพิ่มตารางของเราเป็นสองเท่าของขนาด 2 ^ (n + 1) นั่นหมายความว่าเรากำลังดำเนินการ 2 ^ (n + 1) สำเนาล่าสุดเราดำเนินการ 2 ^ n ก่อนหน้านั้นเราทำ 2 ^ (n-1) ... จนถึง 8,4,2,1 ตอนนี้ถ้าเราเพิ่มสิ่งเหล่านี้เราจะได้ 1 + 2 + 4 + 8 + ... + 2 ^ (n + 1) = 2 ^ (n + 2) - 1 <4 * 2 ^ n = O (2 ^ n) = O (a) การแทรกทั้งหมด (เช่น O (1) เวลาที่ตัดจำหน่าย) นอกจากนี้ควรสังเกตว่าถ้าตารางอนุญาตให้ลบการหดตัวของตารางจะต้องทำที่ปัจจัยอื่น (เช่น 3x)
รายการใน Python นั้นเหมือนกับอาร์เรย์ที่คุณสามารถเก็บค่าได้หลายค่า รายการไม่แน่นอนซึ่งหมายความว่าคุณสามารถเปลี่ยนได้ สิ่งที่สำคัญกว่าที่คุณควรรู้เมื่อเราสร้างรายการ Python จะสร้าง reference_id สำหรับตัวแปรลิสต์นั้นโดยอัตโนมัติ หากคุณเปลี่ยนแปลงโดยกำหนดตัวแปรอื่น ๆ รายการหลักจะเปลี่ยน ลองตัวอย่าง:
list_one = [1,2,3,4]
my_list = list_one
#my_list: [1,2,3,4]
my_list.append("new")
#my_list: [1,2,3,4,'new']
#list_one: [1,2,3,4,'new']
เราผนวกmy_list
แต่รายการหลักของเรามีการเปลี่ยนแปลง รายการของค่าเฉลี่ยนั้นไม่ได้ถูกกำหนดให้เป็นรายการสำเนาที่ได้รับมอบหมายเป็นการอ้างอิง
ในรายการ CPython นั้นถูกนำไปใช้เป็นอาร์เรย์แบบไดนามิกดังนั้นเมื่อเราผนวกในเวลานั้นไม่เพียงเพิ่มแมโครเดียว แต่จะมีการจัดสรรพื้นที่เพิ่มเติมบางส่วนเพื่อไม่ให้มีการเพิ่มพื้นที่ใหม่ทุกครั้ง