Giả sử chúng ta có hai danh sách ____ 2 [n phần tử] và ________ 3 [m phần tử] và chúng ta sử dụng "+" trong Python để hợp nhất hai danh sách thành một, vì vậy
C = A + B;
Câu hỏi của tôi là thời gian chạy của hoạt động này là gì? Dự đoán đầu tiên của tôi là O[n+m]
, không chắc Python có thông minh hơn thế không.
nbro
14.4K27 Huy hiệu vàng104 Huy hiệu bạc188 Huy hiệu đồng27 gold badges104 silver badges188 bronze badges
Đã hỏi ngày 22 tháng 3 năm 2015 lúc 17:54Mar 22, 2015 at 17:54
1
Khi bạn kết hợp hai danh sách với A + B
, bạn sẽ tạo một danh sách hoàn toàn mới trong bộ nhớ. Điều này có nghĩa là dự đoán của bạn là chính xác: độ phức tạp là O[n + m]
[trong đó n
và m
là độ dài của danh sách] vì Python phải lần lượt đi bộ cả hai danh sách để xây dựng danh sách mới.
Bạn có thể thấy điều này xảy ra trong hàm list_concat
trong mã nguồn cho danh sách Python:
static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
Nếu bạn không cần một danh sách mới trong bộ nhớ, thì thường nên tận dụng thực tế là danh sách là có thể thay đổi [và đây là nơi Python thông minh]. Sử dụng
static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
0 là static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
1 trong độ phức tạp có nghĩa là bạn tránh được chi phí của danh sách sao chép static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
2.Sự phức tạp của các hoạt động danh sách khác nhau được liệt kê ở đây trên Wiki Python.
Đã trả lời ngày 22 tháng 3 năm 2015 lúc 17:59Mar 22, 2015 at 17:59
Alex Rileyalex RileyAlex Riley
159K44 Huy hiệu vàng252 Huy hiệu bạc234 Huy hiệu Đồng44 gold badges252 silver badges234 bronze badges
Dự đoán đầu tiên của tôi là
O[n+m]
, không chắc Python có thông minh hơn thế không.
Không có gì có thể thông minh hơn thế trong khi trả lại một bản sao. Mặc dù ngay cả khi
static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
4, static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
5 là các chuỗi bất biến như chuỗi; Cpython vẫn tạo một bản sao đầy đủ thay vì bí danh cùng một bộ nhớ [nó đơn giản hóa việc triển khai bộ sưu tập rác cho các chuỗi như vậy].Trong một số trường hợp cụ thể, hoạt động có thể là
static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
6 tùy thuộc vào những gì bạn muốn làm với kết quả, ví dụ: static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
7 cho phép lặp lại tất cả các mục [nó không tạo ra một bản sao, thay đổi trong static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
4, static PyObject *
list_concat[PyListObject *a, PyObject *bb]
{
/* ...code snipped... */
src = a->ob_item;
dest = np->ob_item;
for [i = 0; i < Py_SIZE[a]; i++] { /* walking list a */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE[a];
for [i = 0; i < Py_SIZE[b]; i++] { /* walking list b */
PyObject *v = src[i];
Py_INCREF[v];
dest[i] = v;
}
/* ...code snipped... */
5 ảnh hưởng đến các mục mang lại]. Hoặc nếu bạn cần một truy cập ngẫu nhiên; Bạn có thể mô phỏng nó bằng cách sử dụng lớp con A = [a1, a2, ..., an]
0, ví dụ: A = [a1, a2, ..., an]
1 nhưng trong trường hợp chung, bản sao và do đó không thể tránh khỏi thời gian chạy O[n+m]
.
Đã trả lời ngày 23 tháng 3 năm 2015 lúc 8:04Mar 23, 2015 at 8:04
JFSJFSjfs
385K183 Huy hiệu vàng949 Huy hiệu bạc1623 Huy hiệu Đồng183 gold badges949 silver badges1623 bronze badges
Sao chép danh sách là A = [a1, a2, ..., an]
3 [với n
là số lượng phần tử] và mở rộng là A = [a1, a2, ..., an]
5 [với A = [a1, a2, ..., an]
6 là số lượng phần tử trong danh sách thứ hai]. Dựa trên hai sự thật này, tôi sẽ nghĩ rằng nó không thể ít hơn A = [a1, a2, ..., an]
7, vì đây là một bản sao và mở rộng hoạt động, và ít nhất bạn sẽ cần sao chép tất cả các yếu tố của cả hai danh sách.
Nguồn: Thời gian Python
CON CHUỘT
8331 Huy hiệu vàng14 Huy hiệu bạc35 Huy hiệu đồng1 gold badge14 silver badges35 bronze badges
Đã trả lời ngày 22 tháng 3 năm 2015 lúc 18:01Mar 22, 2015 at 18:01
TheBlackCatTheBlackcatTheBlackCat
9.2213 Huy hiệu vàng22 Huy hiệu bạc 30 Huy hiệu Đồng3 gold badges22 silver badges30 bronze badges