2011-11-19 2 views
25

Xuất phát từ nền Java, tôi tự hỏi tại sao List trong Scala không có trường size giống như Java tương đương LinkedList. Sau khi tất cả, với một lĩnh vực kích thước bạn sẽ có thể xác định kích thước của danh sách trong thời gian không đổi, vậy tại sao là trường kích thước giảm?Tại sao Danh sách Scala không có trường kích thước?

(Câu hỏi này đề cập đến các lớp học tập mới trong Scala 2.8 và sau đó. Ngoài ra, tôi đang đề cập đến bất biến List, không phải là người có thể thay đổi.)

+1

Đó là 'size()' trong Java, một hàm. – Kapep

+4

Nhưng chức năng được hỗ trợ bởi một trường, mà làm cho nó O (1). Danh sách Scala không có trường như vậy, vì lý do chính đáng, nhưng điều đó làm cho việc truy cập chiều dài O (n). –

+2

"* python * dude" xuất phát từ nền * Java *? * python * không đề cập đến ngôn ngữ, phải không? – huynhjl

Trả lời

25

Người ta không thể nói lĩnh vực kích thước là giảm, dạng danh sách như vậy mà không có kích thước đã tồn tại 50 năm kể từ khi LISP mà họ đang có mặt khắp nơi và họ đang rất phổ biến ở ML và Haskell quá, cả hai đều có ảnh hưởng trong scala.

Lý do cơ bản là danh sách đó là cấu trúc đệ quy. Một không trống ListCons(head: A, tail: List[A]) - ngoại trừ rằng Cons thực ra được gọi là :: để cho phép ký hiệu thuận tiện. Bạn có thể truy cập đuôi (danh sách không có phần tử đầu của nó) và đó cũng là một danh sách. Và điều này được thực hiện chỉ là về tất cả các thời gian. Vì vậy, việc đếm số trong danh sách sẽ không có nghĩa là chỉ thêm một số nguyên, nhưng càng nhiều số nguyên càng có nhiều phần tử. Điều này là khả thi, nhưng chắc chắn không miễn phí.

Nếu bạn so sánh với java LinkedList, LinkedList có triển khai đệ quy (dựa trên Nút, ít nhiều giống như Nhược điểm, nhưng có liên kết theo cả hai hướng). Nhưng LinkedList không phải là một Node, nó sở hữu chúng (và giữ số lượng của chúng). Vì vậy, trong khi nó có một triển khai đệ quy, bạn không thể xử lý nó một cách đệ quy. Bạn muốn đuôi của một LinkedList như một LinkedList, bạn sẽ phải loại bỏ phần đầu và thay đổi danh sách của bạn hoặc sao chép tất cả các phần tử đuôi vào một LinkedList mới. Vì vậy, scala của List và java LinkedList là cấu trúc rất khác nhau.

+0

Danh sách nghiêm ngặt trong scala. Vì vậy, mỗi lần Cons áp dụng nó biết kích thước của đuôi và vì vậy có thể tăng 1 và viết nó vào một lĩnh vực cụ thể. Giống như 'Cons (đầu: A, đuôi: List [A]) {override val size: Int = tail.size + 1}'. Có thể, nhưng có thể được coi là quá đói không gian. – ayvango

3

Bạn đã kiểm tra các lĩnh vực length?

+1

'length' là phương thức truyền tải ngang qua toàn bộ danh sách, do đó có độ phức tạp' O (n) '. OP hỏi tại sao không có trường 'length' * * với truy cập thời gian không đổi. –

+0

@Udo Held: Liên kết của bạn đến từ Scala 2.7.7 mà tôi không có kinh nghiệm. Câu hỏi của tôi dựa trên Scala 2.9+, và cụ thể trong cuốn sách "Lập trình trong Scala", 2nd Ed., Ở đây nó được đề cập trong chương 16 xác định chiều dài của một Danh sách là tuyến tính trong số lượng các phần tử. –

+0

http://www.scala-lang.org/api/current/scala/collection/mutable/LinkedList.html cũng có độ dài là 2.9. Bạn sẽ tìm thấy kích thước ở đó cũng tương đương với chiều dài. –

8

Danh sách định nghĩa kích thước:

> List(1, 2, 3).size 
res4: Int = 3 

trong đó có o tuyến tính (n) thời gian thực hiện. Nếu bạn thực sự cần một thời gian không đổi, bạn nên xem xét ListBuffer có thể thay đổi để cung cấp việc triển khai kích thước thời gian không đổi.

+0

Phiên bản Scala nào? Trước hoặc sau 2.8? –

+0

ít nhất là từ 2.8 trở lên. Xem: http://www.scala-lang.org/api/2.8.0/scala/collection/immutable/List.html – David

+2

Đây có phải là thời gian không đổi không? nó nói "tương đương với chiều dài" –

12

Bởi vì duy trì lĩnh vực này

  1. sẽ Thêm overhead bộ nhớ cho tất cả các danh sách;
  2. Thêm phí thời gian trên mỗi lần tạo danh sách.

Trong Java thông thường, LinkedList được tạo và sau đó thao tác mà không tạo danh sách mới bằng cách thêm/xóa phần tử; ở Scala có rất nhiều số List được tạo.

Vì vậy, nó đã được quyết định rằng chi phí không phải là giá trị nó.

+3

Trên thực tế, việc thêm trường 'size' sẽ * tăng gấp đôi * kích thước của _cons_ từ 8 đến 16 byte, do các đối tượng được phân bổ theo bội số của 8 byte. –

0

Tôi có thiếu gì đó không? Kích thước có ở đó:

Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> import scala.collection.immutable.List 
import scala.collection.immutable.List 

scala> val a = List(1,2,3) 
a: List[Int] = List(1, 2, 3) 

scala> a size 
res0: Int = 3 
+3

chính xác nhưng nó là một o (n) kích thước thực hiện. Chủ đề là việc triển khai thực hiện java LinkedList có một trường kích thước mà làm lại kích thước theo thời gian không đổi. – David

8

"bất lợi" của độ phức tạp O (n) không lớn như bạn nghĩ. Martin Odersky đã đề cập trong một cuộc nói chuyện rằng (nếu tôi nhớ chính xác) 90% của tất cả các danh sách được tạo ra trong tất cả các chương trình bằng bất kỳ ngôn ngữ máy tính nào có kích thước từ 4 trở xuống.Do đó, thời gian truy cập O (n) cho size không phải là chi phí lớn cho hầu hết các danh sách được tạo và, như những người khác đã đề cập ở đây, tiết kiệm bộ nhớ nhiều hơn bù đắp cho điều này.