Những thuật toán / cấu trúc dữ liệu nào tôi nên nhận ra và biết tên? [đóng cửa]


69

Tôi muốn coi mình là một lập trình viên khá có kinh nghiệm. Tôi đã lập trình được hơn 5 năm rồi. Điểm yếu của tôi mặc dù là thuật ngữ. Tôi tự học, vì vậy trong khi tôi biết cách lập trình, tôi không biết một số khía cạnh chính thức hơn của khoa học máy tính. Vì vậy, các thuật toán / cấu trúc dữ liệu thực tế mà tôi có thể nhận ra và biết theo tên là gì?

Lưu ý, tôi không yêu cầu giới thiệu sách về việc triển khai các thuật toán. Tôi không quan tâm đến việc triển khai chúng, tôi chỉ muốn có thể nhận ra khi nào một cấu trúc thuật toán / dữ liệu sẽ là một giải pháp tốt cho một vấn đề. Tôi đang hỏi thêm về danh sách các thuật toán / cấu trúc dữ liệu mà tôi nên "nhận ra". Chẳng hạn, tôi biết giải pháp cho một vấn đề như thế này:

Bạn quản lý một bộ tủ khóa có nhãn 0-999. Mọi người đến với bạn để thuê tủ khóa và sau đó quay lại để trả lại chìa khóa tủ. Làm thế nào bạn có thể xây dựng một phần mềm để quản lý việc biết tủ khóa nào miễn phí và loại nào đang được sử dụng?

Giải pháp, sẽ là một hàng đợi hoặc ngăn xếp.

Những gì tôi đang tìm kiếm là những thứ như "B-Tree nên được sử dụng trong tình huống nào - Nên sử dụng thuật toán tìm kiếm nào ở đây", v.v. Và có thể giới thiệu nhanh về cách cấu trúc dữ liệu phức tạp hơn (nhưng thường được sử dụng) / thuật toán làm việc.

Tôi đã thử xem danh sách các cấu trúc dữ liệuthuật toán của Wikipedia nhưng tôi nghĩ đó là một chút quá mức cần thiết. Vì vậy, tôi đang tìm kiếm nhiều hơn những điều thiết yếu tôi nên nhận ra là gì?


10
Bỏ phiếu để đóng là "không mang tính xây dựng". Bất kỳ câu trả lời sẽ hoàn toàn chủ quan - không có sự đồng thuận về những gì một người "nên" biết.
Oded

2
Phần nào của vấn đề khóa đó yêu cầu thứ tự đầu vào / đầu ra? [gợi ý!]
Telastyn

5
@Oded hoàn toàn có một danh sách mà tôi nghĩ rằng hầu hết mọi người sẽ đồng ý về việc cấu trúc dữ liệu và thuật toán mà một lập trình viên thành thạo nên biết.
David Cowden

6
@Oded Không có sự đồng thuận? Điều gì về giáo trình của một khóa học giới thiệu về thuật toán và cấu trúc dữ liệu trong khoa học máy tính? Khá chuẩn hóa và đánh giá ngang hàng . Một điểm khởi đầu tốt.
MarkJ

3
Giải pháp thay thế; giả sử bạn tính phí theo ngày và tính phí tối đa. Đính kèm thẻ giấy vào chìa khóa khi bạn để tủ khóa và viết số ngày Julian trên đó. Khi khóa được trả lại, hãy nhìn vào thẻ để tính tiền thuê. Các thẻ bị thiếu hoặc sai lệch thu hút phí tối đa. Các khóa không sử dụng được lưu trữ trong một túi (vì không cần phải chọn bất kỳ khóa cụ thể nào từ các phím miễn phí khi để tủ khóa). Tổng kích thước cấu trúc dữ liệu: bit không. Tất cả các phần của thuật toán là O (1).
James Youngman

Câu trả lời:


78

Một phản ứng khách quan:

Mặc dù câu trả lời ban đầu của tôi cho câu hỏi này dựa trên kinh nghiệm thực nghiệm của tôi khi là một sinh viên CS sắp tốt nghiệp và ý kiến ​​dự kiến ​​của tôi về loại người tôi muốn làm việc trong lĩnh vực CS. Thực sự có một mục tiêu (liên quan đến các ý kiến ​​chủ quan của câu trả lời ACM SIGCSE và xã hội điện toán IEEE). Cứ sau 10 năm , các cơ quan ACMIEEE hợp tác trên một ấn phẩm chung có chi tiết đề xuất cho chương trình giảng dạy khoa học máy tính đại học dựa trên kiến ​​thức chuyên môn về tình trạng của ngành công nghiệp điện toán. Thông tin chi tiết có thể được tìm thấy tại cs2013.org . Ủy ban xuất bản một báo cáo cuối cùng liệt kê khuyến nghị chương trình giảng dạy của họ .

Điều đó nói rằng, tôi vẫn nghĩ rằng danh sách của tôi là khá tốt.

Câu trả lời gốc dưới đây.


Tôi nên biết gì?

Tối thiểu

Tôi nghĩ rằng một lập trình viên lão luyện nên có ít nhất kiến ​​thức trình độ đại học về Khoa học Máy tính. Chắc chắn, bạn có thể làm việc hiệu quả trong nhiều công việc chỉ với một tập hợp nhỏ của Khoa học Máy tính vì cộng đồng vững chắc của CS, và sự tập trung của hầu hết các vị trí chuyên nghiệp. Ngoài ra, nhiều người sẽ chuyên sâu hơn sau khi học đại học. Tuy nhiên, tôi không nghĩ một trong hai lý do để không bí mật về kiến ​​thức CS nền tảng.

Để trả lời câu hỏi tiêu đề, đây là những gì một sinh viên CS đại học (nền tảng cho một lập trình viên lão luyện) nên biết khi tốt nghiệp:

Cấu trúc dữ liệu

  • Đại diện dữ liệu máy
    • Những người thân, bổ sung của hai và số học liên quan
    • Từ, Con trỏ, Điểm nổi
    • Truy cập bit, dịch chuyển và thao tác
  • Danh sách liên kết
  • Bảng băm (bản đồ hoặc từ điển)
  • Mảng
  • Cây
  • Ngăn xếp
  • Hàng đợi
  • Đồ thị
  • Cơ sở dữ liệu

Thuật toán

  • Sắp xếp:
    • Sắp xếp bong bóng (để biết tại sao nó xấu)
    • Sắp xếp chèn
    • Hợp nhất sắp xếp
    • Sắp xếp nhanh chóng
    • Sắp xếp kiểu Radix, Sắp xếp đếm và Sắp xếp nhóm
    • Sắp xếp đống
    • Sắp xếp lượng tử và lượng tử (=
  • Đang tìm kiếm:
    • Tìm kiếm tuyến tính
    • Tìm kiếm nhị phân
    • Độ sâu tìm kiếm đầu tiên
    • Bề rộng tìm kiếm đầu tiên
  • Thao tác chuỗi
  • Lặp lại
  • Cây thông
  • Liệt kê danh sách
  • Hàm băm
  • Triển khai cụ thể Bảng Hash, Cây, Danh sách, Ngăn xếp, Hàng đợi, Mảng và Bộ hoặc Bộ sưu tập
  • Thuật toán lập lịch
  • Hệ thống tệp Traversal và Thao tác (ở mức inode hoặc mức tương đương).

Mẫu thiết kế

  • Mô đun hóa
  • Nhà máy
  • Người xây dựng
  • Người độc thân
  • Bộ chuyển đổi
  • Người trang trí
  • Cân nặng
  • Người quan sát
  • Lặp lại
  • Nhà nước [Máy]
  • Bộ điều khiển xem mô hình
  • Các mẫu lập trình và xử lý song song

Nghịch lý

  • Bắt buộc
  • Hướng đối tượng
  • Chức năng
  • Tuyên bố
  • Lập trình tĩnh và động
  • Đánh dấu dữ liệu

Lý thuyết phức tạp

  • Không gian phức tạp
  • Khả năng tính toán
  • Ngôn ngữ hoàn chỉnh thông thường, không có ngữ cảnh và phổ biến
  • Biểu thức chính quy
  • Bộ đếm và kết hợp cơ bản

Vượt ra ngoài

Để tìm hiểu những gì bạn hỏi về câu hỏi sau này, nếu bạn quen thuộc với câu hỏi trên, bạn có thể dễ dàng xác định mô hình, thuật toán và cấu trúc dữ liệu phù hợp cho một kịch bản nhất định. Tuy nhiên, bạn nên nhận ra rằng thường không có giải pháp tốt nhất. Đôi khi bạn có thể được yêu cầu chọn ít hơn hai tệ nạn hoặc thậm chí chỉ cần chọn giữa hai giải pháp khả thi như nhau. Bởi vì điều này, bạn cần có kiến ​​thức chung để có thể bảo vệ sự lựa chọn của bạn chống lại các đồng nghiệp của bạn.

Dưới đây là một số mẹo cho thuật toán và cấu trúc dữ liệu:

  • Tìm kiếm nhị phân chỉ có thể (và nên) được sử dụng trên dữ liệu được sắp xếp.
  • Các kiểu sắp xếp Radix là tuyệt vời, nhưng chỉ khi bạn có các lớp hữu hạn của những thứ được sắp xếp.
  • Cây xanh tốt cho hầu hết mọi thứ như Bảng Hash. Chức năng của Bảng Hash có thể được ngoại suy và sử dụng để giải quyết nhiều vấn đề với chi phí hiệu quả.
  • Mảng có thể được sử dụng để sao lưu hầu hết các cấu trúc dữ liệu cấp cao hơn. Đôi khi một "cấu trúc dữ liệu" không hơn một số phép toán thông minh để truy cập các vị trí trong một mảng.
  • Sự lựa chọn ngôn ngữ có thể là sự khác biệt giữa việc nhổ tóc của bạn, hoặc lướt qua, một vấn đề.
  • Bảng ASCII và mảng 128 phần tử tạo thành bảng băm ẩn (=
  • Các biểu thức thông thường có thể giải quyết rất nhiều vấn đề, nhưng chúng không thể được sử dụng để phân tích HTML .
  • Đôi khi cấu trúc dữ liệu cũng quan trọng như thuật toán.

Một số ở trên có vẻ như không có trí tuệ, và một số có vẻ mơ hồ. Nếu bạn muốn tôi đi vào chi tiết hơn, tôi có thể. Nhưng, hy vọng của tôi là khi gặp một câu hỏi cụ thể hơn, chẳng hạn như: "Thiết kế hàm đếm số lần xuất hiện của mỗi ký tự trong Chuỗi", bạn nhìn vào mẹo về bảng ASCII và 128 mảng phần tử tạo thành hàm băm gọn gàng bảng cho câu trả lời.

Dựa trên những ý tưởng này, tôi sẽ đề xuất một câu trả lời cho vấn đề tủ khóa được nêu trong câu hỏi của bạn.


Trả lời cho vấn đề đặt ra trong câu hỏi của bạn.

Đây có thể không phải là câu trả lời tốt nhất cho câu hỏi của bạn, nhưng tôi nghĩ đó là một câu hỏi thú vị không đòi hỏi bất cứ điều gì quá phức tạp. Và nó chắc chắn sẽ đánh bại sự phức tạp về thời gian của việc sử dụng hàng đợi hoặc ngăn xếp đòi hỏi thời gian tuyến tính để xác định xem khóa có miễn phí hay không.

Bạn có tủ khóa 0-999. Bây giờ, vì bạn có số lượng tủ khóa cố định, bạn có thể dễ dàng hình thành chức năng băm mà không có va chạm trong phạm vi 0-999. Hàm này chỉ đơn giản là h (x) = x mod 1000. Bây giờ, [về mặt khái niệm] xây dựng bảng băm với các khóa nguyên và nội dung của mảng char 1000 phần tử làm giá trị của bạn. Nếu khách hàng muốn dự trữ khóa 78 để sử dụng, chỉ cần đặt 78 vào hàm băm (trả về 78), sau đó thêm số đó vào con trỏ cơ sở của mảng - lưu trữ giá trị thực tại vị trí được chỉ ra bởi giá trị offset . Tương tự, nếu bạn cần kiểm tra xem 78 có được sử dụng hay không, chỉ cần đọc giá trị được lưu trữ tại vị trí đó và kiểm tra lại có đúng không.

Giải pháp này hoạt động trong thời gian không đổi cho việc tra cứu và lưu trữ trái ngược với lưu trữ thời gian (n) và tra cứu trong trường hợp hàng đợi ưu tiên được hỗ trợ bởi cây nhị phân. Mô tả có chủ ý dài dòng để bạn có thể thấy các khái niệm cao hơn được đưa vào một thuật toán hiệu quả.

Bây giờ, bạn có thể hỏi, nếu tôi cần biết tất cả các tủ khóa có sẵn, thì hàng đợi ưu tiên sẽ tốt hơn không? Nếu có k khóa có sẵn trong hàng ưu tiên, lặp đi lặp lại tất cả chúng sẽ thực hiện k bước. Hơn nữa, tùy thuộc vào việc thực hiện hàng đợi ưu tiên của bạn, bạn có thể phải xây dựng lại hàng đợi ưu tiên của mình khi bạn xem xét tất cả .. sẽ mất các bước k * log (k): (k <1000). Trong giải pháp mảng, bạn chỉ phải lặp lại một mảng 1000 phần tử và kiểm tra xem cái nào đang mở. Bạn cũng có thể thêm một danh sách có sẵn hoặc được sử dụng vào triển khai để chỉ kiểm tra thời gian k.


1
Câu trả lời chính xác! Tôi cũng muốn nói thêm rằng bạn thực sự nên tự tin khi sử dụng các hàm / cơ sở dữ liệu được xác định trước của ngôn ngữ bạn đang sử dụng, ví dụ như thuật toán và cấu trúc dữ liệu stl trong C ++ hoặc API Java cho Java.
marktani

1
Xuất sắc! Đặc biệt là "Biểu thức thông thường có thể giải quyết rất nhiều vấn đề, nhưng chúng không thể được sử dụng để phân tích HTML."
Thất vọngWithFormsDesigner

2
Câu trả lời là tốt, cho đến khi "vấn đề" xuất hiện. Hoàn toàn không có lý do để sử dụng hàng đợi ưu tiên hoặc bảng băm. Một ngăn xếp đơn giản là đủ. Thêm lần lặp để có được danh sách đầy đủ các tủ khóa miễn phí nếu bạn muốn.
Matthieu M.

1
chúng ta có nên thêm cơ sở dữ liệu quan hệ + SQL, kiến ​​thức về cây B +, lý thuyết trình biên dịch, tổ chức phần cứng kiến ​​thức, kiến ​​thức về lý thuyết hệ điều hành, kiến ​​thức về mạng TCP / IP không?
dan_l

1
Tôi nghi ngờ về các mẫu thiết kế. Nhiều ngôn ngữ hữu ích trong một số loại ngôn ngữ trong khi vô dụng và / hoặc không cần thiết ở những ngôn ngữ khác. Bạn cũng có thể muốn thêm Heuristic theo thuật toán và cấu trúc dữ liệu trie và danh sách bỏ qua. Các thuật toán / cấu trúc dữ liệu truyền thống đạt đến giới hạn truy cập đồng bộ nhưng có thể bị đánh bại bởi các cách tiếp cận phi truyền thống khác bằng cách sử dụng nhiều luồng và đồng thời. Heuristic có thể giảm đáng kể số lượng tra cứu cần thiết trong khi các cấu trúc như danh sách bỏ qua sẽ cho phép cấu trúc dữ liệu được ghi vào mà không cần khóa toàn cầu.
Evan Plaice

6

Hướng dẫn thiết kế thuật toán của Steven S. Skiena có vẻ giống như nguồn bạn đang tìm kiếm. Phần thứ hai là một danh sách phân loại các vấn đề với việc xem xét các thuật toán liên quan. Có một phiên bản web .


3
cuốn sách tuyệt vời, nhưng đừng cảm thấy bạn phải thành thạo tất cả để trở thành một lập trình viên. Tôi mới mua nó gần đây và tôi đã được trả tiền cho chương trình từ năm 1979. (Và vâng, tôi đã mua nó với niềm tin tôi có thể học được điều gì đó từ nó.)
Kate Gregory

@KateGregory Tôi đã mua cuốn sách và thực sự không thể hiểu được vì tôi chỉ biết các ngôn ngữ cấp cao như Ruby và Javascript (không có cây nhị phân, danh sách được liên kết, v.v.) ... Cuối cùng tôi đã từ bỏ việc đọc nó.
bigpotato

4

Không có "nên". A. Làm quen với các lớp phức tạp cơ bản (tuyến tính, logarit, v.v.) B. Nhận ra rằng bạn có thể làm bất cứ điều gì với một mảng đơn giản như bạn có thể với cấu trúc dữ liệu ưa thích như cây B. Bí quyết trong việc lựa chọn cấu trúc / thuật toán phù hợp nằm ở việc cân bằng hiệu năng, kích thước đầu vào dự kiến ​​và độ phức tạp thực hiện.

Sau đó, có những thứ trừu tượng nhưng vô cùng hữu ích (mặc dù tính hữu dụng không rõ ràng ngay lập tức): máy trạng thái, lý thuyết đồ thị, lý thuyết lồi (lập trình tuyến tính, v.v.).


1
Đừng đánh giá thấp tầm quan trọng của việc biết khi nào nên sử dụng cái gì. Bởi vì những vấn đề bạn đã giải quyết bằng cách sử dụng một mảng đơn giản sẽ quay trở lại và cắn bạn ngay khi bạn chuẩn bị quay lại trong ứng dụng khách lớn đó và phát hiện ra ứng dụng của bạn hoạt động tốt trong nhiều năm chậm lại chỉ vì bạn sử dụng bong bóng thay vì một quicksort.
Pieter B

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.