Các loại cấu trúc dữ liệu là gì? Cấu trúc dữ liệu: khái niệm chung, cách thực hiện. Cấu trúc dữ liệu đơn giản nhất: hàng đợi, ngăn xếp. Sử dụng ngăn xếp và ký hiệu Ba Lan đảo ngược

Khái niệm về cấu trúc dữ liệu rất cơ bản nên rất khó để tìm ra một định nghĩa đơn giản cho nó. Nhiệm vụ trở nên dễ dàng hơn nếu chúng ta cố gắng hình thành khái niệm này liên quan đến các kiểu dữ liệu và biến. Như bạn đã biết, chương trình là sự thống nhất của một thuật toán (thủ tục, hàm) và dữ liệu chúng xử lý. Ngược lại, dữ liệu được xác định bởi các kiểu dữ liệu cơ bản và dữ liệu phái sinh - các biểu diễn “lý tưởng” của các biến chiều cố định với các tập hợp các phép toán đã biết trên chúng và các thành phần của chúng. Các biến được đặt tên là các vùng bộ nhớ mà các kiểu dữ liệu được xây dựng được "ánh xạ".
Trong một chương trình, luôn có thể phân biệt các nhóm biến có liên quan gián tiếp (bằng cách sử dụng dữ liệu trong cùng một thủ tục và hàm) và nhóm có liên quan trực tiếp (bằng sự hiện diện của các mối quan hệ thông qua con trỏ). Theo phép tính gần đúng đầu tiên, chúng có thể được coi là cấu trúc dữ liệu.

Có các cấu trúc (loại) dữ liệu ĐƠN GIẢN (cơ bản, nguyên thủy) và TÍCH HỢP (có cấu trúc, tổng hợp, phức tạp). Cấu trúc dữ liệu đơn giản là những cấu trúc không thể chia thành các thành phần lớn hơn bit. Từ quan điểm của cấu trúc vật lý, thực tế quan trọng là trong một kiến ​​trúc máy nhất định, trong một hệ thống lập trình nhất định, chúng ta luôn có thể biết trước kích thước của một kiểu đơn giản nhất định sẽ là bao nhiêu và cấu trúc vị trí của nó trong đó như thế nào. bộ nhớ sẽ được. Từ quan điểm logic, dữ liệu đơn giản là những đơn vị không thể chia cắt được. Tích hợp là những cấu trúc dữ liệu có thành phần là các cấu trúc dữ liệu khác - đơn giản hoặc được tích hợp. Cấu trúc dữ liệu tích hợp được lập trình viên xây dựng bằng cách sử dụng các công cụ tích hợp dữ liệu do ngôn ngữ lập trình cung cấp.

Tùy thuộc vào sự vắng mặt hay hiện diện của các kết nối được xác định rõ ràng giữa các thành phần dữ liệu, người ta nên phân biệt giữa các cấu trúc DISCONNECTED (vectơ, mảng, chuỗi, ngăn xếp, hàng đợi) và cấu trúc LINKED (danh sách liên kết).

Một tính năng rất quan trọng của cấu trúc dữ liệu là tính biến đổi của nó - sự thay đổi về số lượng phần tử và (hoặc) kết nối giữa các phần tử của cấu trúc. Định nghĩa về tính biến đổi của cấu trúc không phản ánh thực tế là giá trị của các phần tử dữ liệu thay đổi, vì trong trường hợp này tất cả các cấu trúc dữ liệu sẽ có đặc tính có thể thay đổi. Dựa trên tính biến đổi, các cấu trúc được phân biệt: TÌNH TRẠNG, BÁN TÌNH TRẠNG, ĐỘNG. Việc phân loại cấu trúc dữ liệu dựa trên tính biến đổi được thể hiện trong Hình 2. 1.1. Cấu trúc dữ liệu cơ bản, tĩnh, bán tĩnh và động, là đặc trưng của RAM và thường được gọi là cấu trúc hoạt động. Cấu trúc tệp tương ứng với cấu trúc dữ liệu của bộ nhớ ngoài.



Cơm. 1.1. Phân loại cấu trúc dữ liệu

Một tính năng quan trọng của cấu trúc dữ liệu là tính chất sắp xếp của các phần tử của nó. Dựa trên đặc điểm này, các cấu trúc có thể được chia thành các cấu trúc LINEAR và Non-LINEAR.

Tùy thuộc vào bản chất của sự sắp xếp tương đối của các phần tử trong bộ nhớ, các cấu trúc tuyến tính có thể được chia thành các cấu trúc với sự phân bố các phần tử trong bộ nhớ THEO HIỆU QUẢ (vectơ, chuỗi, mảng, ngăn xếp, hàng đợi) và các cấu trúc với sự phân bố các phần tử trong bộ nhớ LIÊN KẾT TÙY Ý (đơn giản là danh sách liên kết, liên kết đôi). Một ví dụ về cấu trúc phi tuyến là danh sách, cây, đồ thị đa liên kết.

Trong các ngôn ngữ lập trình, khái niệm “cấu trúc dữ liệu” có liên quan chặt chẽ với khái niệm “kiểu dữ liệu”. Bất kỳ dữ liệu nào, tức là các hằng, biến, giá trị hàm hoặc biểu thức được đặc trưng bởi kiểu của chúng.

Thông tin cho từng loại xác định rõ ràng:

· 1) cấu trúc lưu trữ dữ liệu thuộc loại được chỉ định, tức là một mặt, phân bổ bộ nhớ và biểu diễn dữ liệu trong đó, mặt khác, diễn giải biểu diễn nhị phân;

· 2) tập hợp các giá trị cho phép mà đối tượng này hoặc đối tượng kia thuộc loại được mô tả có thể có;

· 3) một tập hợp các thao tác hợp lệ có thể áp dụng cho một đối tượng thuộc loại được mô tả.

CẤU TRÚC DỮ LIỆU là một tập hợp các biến vật lý (kiểu dữ liệu) và logic (thuật toán, hàm) có liên quan với nhau và các giá trị của chúng.

Lưu ý rằng khái niệm cấu trúc dữ liệu không chỉ liên quan đến các biến tạo nên nó mà còn liên quan đến các thuật toán (hàm) không chỉ kết nối logic các biến với nhau mà còn xác định các giá trị bên trong cũng phải đặc trưng của cấu trúc dữ liệu này. Ví dụ: một chuỗi các giá trị dương được đặt trong một mảng và có thứ nguyên thay đổi (cấu trúc dữ liệu) có thể có dấu phân cách null. Tất cả các hoạt động tạo và kiểm tra bộ giới hạn này đều được thực hiện bởi các hàm. Vì vậy, chúng ta có thể nói rằng một phần quan trọng của cấu trúc dữ liệu được “kết nối cứng” trong các thuật toán xử lý nó.
Phương pháp xác định biến thông qua các kiểu dữ liệu mà chúng ta đã biết có đặc điểm là, thứ nhất, số lượng biến trong chương trình là cố định và thứ hai, thứ nguyên của chúng không thể thay đổi trong khi chương trình đang chạy. Nếu mối quan hệ giữa các biến này ít nhiều không đổi thì cấu trúc dữ liệu đó có thể được gọi là tĩnh.

CẤU TRÚC DỮ LIỆU TĨNH - một tập hợp gồm một số biến cố định có thứ nguyên không đổi với bản chất không thay đổi của các kết nối giữa chúng
Ngược lại, nếu một trong các tham số của cấu trúc dữ liệu—số lượng biến, thứ nguyên của chúng hoặc mối quan hệ giữa chúng—thay đổi trong khi chương trình đang chạy thì cấu trúc dữ liệu đó được gọi là động.

CẤU TRÚC DỮ LIỆU ĐỘNG - một tập hợp các biến, số lượng, thứ nguyên hoặc bản chất của các mối quan hệ giữa chúng thay đổi trong quá trình vận hành chương trình.

Cấu trúc dữ liệu động dựa trên hai thành phần ngôn ngữ lập trình:

· Các biến động, số lượng các biến này có thể thay đổi và cuối cùng được xác định bởi chính chương trình. Ngoài ra, khả năng tạo mảng động cho phép chúng ta nói về dữ liệu có kích thước thay đổi;

· con trỏ cung cấp mối quan hệ trực tiếp giữa dữ liệu và khả năng thay đổi các kết nối này.

Do đó, định nghĩa sau đây gần đúng: cấu trúc dữ liệu động là các biến và mảng động được liên kết bởi các con trỏ.
Nói về cấu trúc dữ liệu, chúng ta không được quên rằng các biến thông thường nằm trong RAM (bộ nhớ trong của máy tính). Do đó, cấu trúc dữ liệu thường liên quan đến bộ nhớ. Tuy nhiên, cũng có bộ nhớ ngoài, trong ngôn ngữ này có thể truy cập gián tiếp thông qua các toán tử (Pascal) hoặc các hàm (C) hoạt động với các tệp. Trong chế độ truy cập ngẫu nhiên nhị phân, bất kỳ tệp nào cũng tương tự như vùng bộ nhớ có thể định địa chỉ trực tiếp không giới hạn, nghĩa là, theo quan điểm của chương trình, nó trông giống như bộ nhớ thông thường. Đương nhiên, chương trình có thể sao chép các biến từ bộ nhớ đến một vị trí tùy ý trong tệp và ngược lại, do đó sắp xếp mọi cấu trúc dữ liệu (bao gồm cả động) trong tệp.
Cấu trúc dữ liệu là người thực thi, tổ chức công việc với dữ liệu, bao gồm lưu trữ, thêm và xóa, sửa đổi, tìm kiếm, v.v. Cấu trúc dữ liệu duy trì một thứ tự truy cập nhất định vào nó. Cấu trúc dữ liệu có thể được coi là một loại kho hoặc thư viện. Khi mô tả cấu trúc dữ liệu, bạn cần liệt kê tập hợp các hành động có thể thực hiện được đối với cấu trúc đó và mô tả rõ ràng kết quả của từng hành động. Chúng ta sẽ gọi những hành động đó là quy định. Từ quan điểm lập trình, một hệ thống quy định cấu trúc dữ liệu tương ứng với một tập hợp các hàm hoạt động trên các biến chung.
Cấu trúc dữ liệu được triển khai thuận tiện nhất trong các ngôn ngữ hướng đối tượng. Trong đó, cấu trúc dữ liệu tương ứng với một lớp, bản thân dữ liệu được lưu trữ trong các biến thành viên của lớp (hoặc dữ liệu được truy cập thông qua các biến thành viên) và một tập hợp các phương thức lớp tương ứng với một hệ thống quy định. Theo quy định, trong các ngôn ngữ hướng đối tượng, cấu trúc dữ liệu được triển khai dưới dạng thư viện các lớp tiêu chuẩn: đây là những lớp được gọi là lớp chứa của ngôn ngữ C++, được bao gồm trong thư viện lớp STL tiêu chuẩn hoặc các lớp triển khai nhiều loại khác nhau. cấu trúc dữ liệu từ thư viện Bộ công cụ phát triển Java của ngôn ngữ Java.
Tuy nhiên, cấu trúc dữ liệu có thể được triển khai thành công bằng các ngôn ngữ lập trình truyền thống như Fortran hoặc C. Trong trường hợp này, bạn nên tuân thủ phong cách lập trình hướng đối tượng: xác định rõ ràng một tập hợp các hàm hoạt động với cấu trúc dữ liệu và giới hạn quyền truy cập vào dữ liệu chỉ đối với tập hợp hàm này. Bản thân dữ liệu được triển khai dưới dạng biến tĩnh (không phải toàn cục). Khi lập trình bằng ngôn ngữ C, cấu trúc dữ liệu tương ứng với hai tệp có văn bản nguồn:
1. tiêu đề hoặc tệp h, mô tả giao diện của cấu trúc dữ liệu, tức là. một tập các nguyên mẫu hàm tương ứng với một hệ thống các quy định về cấu trúc dữ liệu;
2. Tệp triển khai hoặc tệp C, xác định các biến tĩnh lưu trữ và truy cập dữ liệu, đồng thời thực hiện các chức năng tương ứng với hệ thống yêu cầu cấu trúc dữ liệu
Cấu trúc dữ liệu thường được triển khai dựa trên cấu trúc cơ sở đơn giản hơn đã được triển khai hoặc dựa trên một mảng và một tập hợp các biến đơn giản. Cần phân biệt rõ ràng giữa việc mô tả cấu trúc dữ liệu theo quan điểm logic và mô tả việc triển khai nó. Có thể có nhiều cách triển khai khác nhau, nhưng từ quan điểm logic (tức là từ quan điểm của người dùng bên ngoài), tất cả chúng đều tương đương và có lẽ chỉ khác nhau ở tốc độ thực hiện các hướng dẫn.

  • Dịch

Tất nhiên, bạn có thể là một lập trình viên thành công mà không cần có kiến ​​thức thiêng liêng về cấu trúc dữ liệu, nhưng chúng hoàn toàn không thể thiếu trong một số ứng dụng. Ví dụ: khi bạn cần tính toán đường đi ngắn nhất giữa hai điểm trên bản đồ hoặc tìm tên trong danh bạ điện thoại có chứa một triệu mục nhập. Chưa kể, cấu trúc dữ liệu luôn được sử dụng trong lập trình thể thao. Chúng ta hãy xem xét một số trong số họ chi tiết hơn.

Xếp hàng

Vì vậy hãy gửi lời chào tới Loopy!

Loopy thích chơi khúc côn cầu với gia đình. Và khi nói đến “trò chơi”, ý tôi là:

Khi rùa bay vào cổng, chúng sẽ bị ném lên trên cùng của chồng. Lưu ý rằng con rùa đầu tiên được thêm vào đống là người đầu tiên rời khỏi đống đó. Nó được gọi là Xếp hàng. Cũng giống như hàng đợi mà chúng ta thấy trong cuộc sống hàng ngày, phần tử đầu tiên được thêm vào danh sách là phần tử đầu tiên rời khỏi nó. Cấu trúc này còn được gọi là FIFO(Vào trước ra trước).

Còn các thao tác chèn và xóa thì sao?

Q = def Insert(elem): q.append(elem) #thêm một phần tử vào cuối hàng đợi print q def delete(): q.pop(0) #xóa phần tử 0 khỏi hàng đợi print q

Cây rơm

Sau một trận khúc côn cầu vui nhộn, Loopy làm bánh kếp cho mọi người. Cô ấy xếp chúng thành một đống.

Khi tất cả các chiếc bánh đã sẵn sàng, Loopy sẽ phục vụ từng chiếc một cho cả gia đình.

Lưu ý rằng chiếc bánh đầu tiên cô ấy làm sẽ được phục vụ sau cùng. Nó được gọi là Cây rơm. Phần tử cuối cùng được thêm vào danh sách sẽ là phần tử đầu tiên rời khỏi danh sách. Cấu trúc dữ liệu này còn được gọi là LIFO(Vào sau ra trước).

Thêm và xóa các phần tử?

S = def Push(elem): #Thêm một phần tử vào ngăn xếp - Push s.append(elem) print s def customPop(): #Xóa một phần tử khỏi ngăn xếp - Pop s.pop(len(s)-1) in s

Đống

Bạn đã bao giờ nhìn thấy một tháp mật độ chưa?

Tất cả các phần tử từ trên xuống dưới đều được đặt ở vị trí của chúng, theo mật độ của chúng. Điều gì xảy ra nếu bạn ném một vật mới vào bên trong?

Nó sẽ chiếm không gian tùy thuộc vào mật độ của nó.

Đại khái đây là cách nó hoạt động Đống.

Đống là một cây nhị phân. Điều này có nghĩa là mỗi phần tử cha có hai phần tử con. Và mặc dù chúng ta gọi cấu trúc dữ liệu này là heap nhưng nó được thể hiện thông qua một mảng thông thường.
Ngoài ra, heap luôn có chiều cao logn, trong đó n là số phần tử

Hình vẽ hiển thị vùng heap tối đa dựa trên quy tắc sau: trẻ em ít hơn cha mẹ. Ngoài ra còn có các đống min-heap, nơi trẻ em luôn có hơn cha mẹ.

Một số hàm đơn giản để làm việc với đống:

Global heap toàn cầu currSize def parent(i): #Lấy chỉ mục của phần tử cha cho phần tử thứ i return i/2 def left(i): #Lấy phần tử con bên trái của phần tử thứ i return 2*i def right (i): #Nhận đúng con của trả về thứ i (2*i + 1)

Thêm một phần tử vào vùng heap hiện có
Để bắt đầu, chúng ta thêm một phần tử vào cuối heap, tức là đến cuối mảng. Sau đó, chúng tôi hoán đổi nó với phần tử gốc cho đến khi nó khớp vào vị trí.

Thuật toán:

  1. Thêm một phần tử vào cuối heap.
  2. So sánh phần tử được thêm vào với phần tử gốc; Nếu đúng thứ tự, chúng tôi dừng lại.
  3. Nếu không, hãy hoán đổi các phần tử và quay lại điểm trước đó.
Mã số:

Def swap(a, b): #swap phần tử có chỉ mục a cho phần tử có chỉ mục b temp = heap[a] heap[a] = heap[b] heap[b] = temp def Insert(elem): Global currSize chỉ mục = len(heap) heap.append(elem) currSize += 1 par = parent(index) flag = 0 while flag != 1: if index == 1: #We đã đạt đến phần tử gốc flag = 1 elif heap > elem : #Nếu chỉ mục của phần tử gốc lớn hơn chỉ mục của phần tử của chúng tôi - phần tử của chúng tôi ở đúng vị trí của nó flag = 1 else: #Hoán đổi phần tử cha bằng swap(par, index) index = par par = parent(index) ) đống in
Số lần vượt qua tối đa của vòng lặp while bằng chiều cao của cây hoặc logn, do đó độ phức tạp của thuật toán là O(logn).

Truy xuất phần tử heap tối đa
Phần tử đầu tiên trong heap luôn là phần tử tối đa, vì vậy chúng ta sẽ chỉ cần xóa nó (sau khi ghi nhớ nó trước) và thay thế bằng phần tử thấp nhất. Sau đó chúng ta sẽ sắp xếp heap theo đúng thứ tự bằng cách sử dụng hàm:

MaxHeapify().

Thuật toán:

  1. Thay thế phần tử gốc bằng phần tử dưới cùng.
  2. So sánh phần tử gốc mới với phần tử con của nó. Nếu chúng theo đúng thứ tự thì dừng lại.
  3. Nếu không, hãy thay thế phần tử gốc bằng một trong các phần tử con (nhỏ hơn cho vùng heap tối thiểu, lớn hơn cho vùng heap tối đa) và lặp lại bước 2.

Def extractMax(): toàn cầu currSize if currSize != 0: maxElem = heap heap = heap #Thay thế phần tử gốc bằng phần tử cuối cùng heap.pop(currSize) #Xóa phần tử cuối cùng currSize -= 1 #Giảm kích thước heap maxHeapify( 1) return maxElem def maxHeapify(index): toàn cầu currSize lar = index l = left(index) r = right(index) #Tính toán phần tử con nào lớn hơn; nếu nó lớn hơn cái gốc, đổi chỗ nếu l<= currSize and heap[l] >đống: lar = l nếu r<= currSize and heap[r] >heap: lar = r if lar != index: swap(index, lar) maxHeapify(lar)
Một lần nữa, số lượng lệnh gọi tối đa đến hàm maxHeapify bằng với chiều cao của cây hoặc logn, có nghĩa là độ phức tạp của thuật toán là O(logn).

Chúng tôi tạo một đống từ bất kỳ mảng ngẫu nhiên nào
Được rồi, có hai cách để làm điều này. Đầu tiên là chèn từng phần tử vào heap một. Nó đơn giản, nhưng hoàn toàn không hiệu quả. Độ phức tạp của thuật toán trong trường hợp này sẽ là O(nlogn), vì hàm O(logn) sẽ được thực thi n lần.

Một cách hiệu quả hơn là sử dụng hàm maxHeapify cho ‘ đống phụ', từ (currSize/2) đến phần tử đầu tiên.

Độ phức tạp sẽ là O(n), và thật không may, bằng chứng của tuyên bố này nằm ngoài phạm vi của bài viết này. Chỉ cần hiểu rằng các phần tử trong phần currSize/2 đến currSize của heap không có phần tử con và hầu hết các 'đống con' được tạo theo cách này sẽ có chiều cao nhỏ hơn chiều cao đăng nhập.

Def buildHeap(): toàn cục currSize cho i in range(currSize/2, 0, -1): #đối số thứ ba trong range() là bước tìm kiếm, trong trường hợp này nó xác định hướng. print heap maxHeapify(i) currSize = len(heap)-1

Thực sự, tại sao tất cả điều này là?

Cần có các đống để thực hiện một kiểu sắp xếp đặc biệt được gọi là, thật kỳ lạ, “ sắp xếp đống" Không giống như “sắp xếp chèn” và “sắp xếp bong bóng” kém hiệu quả hơn với độ phức tạp O(n2) khủng khiếp, “sắp xếp đống” có độ phức tạp O(nlogn).

Việc thực hiện rất đơn giản. Chỉ cần tiếp tục lấy phần tử (gốc) tối đa từ vùng heap một cách tuần tự và ghi nó vào mảng cho đến khi vùng heap trống.

Def heapSort(): for i in range(1, len(heap)): print heap heap.insert(len(heap)-i, extractMax()) #insert phần tử lớn nhất vào cuối mảng currSize = len( đống)-1
Để tóm tắt tất cả những điều trên, tôi đã viết một vài dòng mã chứa các hàm để làm việc với vùng heap và đối với những người hâm mộ OOP, tôi đã định dạng mọi thứ dưới dạng một lớp.

Dễ dàng phải không? Đây là lễ kỷ niệm Loopy!

Băm

Loopy muốn dạy các con mình nhận biết hình dạng và màu sắc. Để làm điều này, cô đã mang về nhà một số lượng lớn các hình vẽ đầy màu sắc.

Sau một thời gian, lũ rùa trở nên hoàn toàn bối rối

Vì vậy, cô ấy đã lấy ra một món đồ chơi khác để giúp quá trình này dễ dàng hơn một chút.

Mọi việc trở nên dễ dàng hơn nhiều vì rùa đã biết rằng các hình được sắp xếp theo hình dạng. Điều gì sẽ xảy ra nếu chúng ta dán nhãn cho mọi trụ cột?

Bây giờ rùa cần kiểm tra một cây cột có một số nhất định và chọn cây cột phù hợp từ số lượng hình nhỏ hơn nhiều. Điều gì sẽ xảy ra nếu chúng ta cũng có một trụ cột riêng cho từng sự kết hợp giữa hình dạng và màu sắc?

Giả sử số cột được tính như sau:

Họ và tên mùa hè tre quảng trường
f+i+o+t+r+e = 22+10+16+20+18+6 = Cột 92

Kra buồn ngủ thẳng Tam giác
k+p+a+p+p+i = 12+18+1+17+18+33 = Cột 99

Chúng ta biết rằng 6*33 = 198 kết hợp có thể có, nghĩa là chúng ta cần 198 cột.

Hãy gọi công thức này để tính số cột - Hàm băm.

Mã số:
def hashFunc(mảnh): Words = Piece.split(" ") #chia chuỗi thành các từ color = Words Shape = Words poleNum = 0 for i in range(0, 3): poleNum += ord(colour[i]) - 96 cựcNum += ord(shape[i]) - 96 cực trả vềNum
(với chữ Cyrillic thì phức tạp hơn một chút, nhưng tôi để nó như vậy cho đơn giản. - khoảng)

Bây giờ, nếu chúng ta tìm ra nơi lưu trữ hình vuông màu hồng, chúng ta có thể tính:
hashFunc("hình vuông màu hồng")

Đây là ví dụ về bảng băm trong đó vị trí của các phần tử được xác định bởi hàm băm.
Với cách tiếp cận này, thời gian tìm kiếm bất kỳ phần tử nào không phụ thuộc vào số lượng phần tử, tức là. O(1). Nói cách khác, thời gian tìm kiếm trong bảng băm là một giá trị không đổi.

Được rồi, nhưng giả sử chúng ta đang tìm kiếm “ xe hơi amel thẳng tam giác” (tất nhiên nếu có màu “caramel”).

HashFunc("hình chữ nhật caramel")
sẽ trả về cho chúng ta 99, đó là con số tương tự cho hình chữ nhật màu đỏ. Nó được gọi là " Va chạm" Để giải quyết xung đột chúng ta sử dụng “ Phương pháp chuỗi”, ngụ ý rằng mỗi cột lưu trữ một danh sách mà chúng tôi tìm kiếm bản ghi mà chúng tôi cần.

Vì vậy, chúng ta chỉ cần đặt hình chữ nhật kẹo lên hình màu đỏ và chọn một hình khi hàm băm trỏ đến cột đó.

Chìa khóa cho một bảng băm tốt là chọn một hàm băm thích hợp. Đây rõ ràng là điều quan trọng nhất trong việc tạo bảng băm và mọi người dành rất nhiều thời gian để phát triển các hàm băm chất lượng.
Trong các bảng tốt, không có vị trí nào chứa nhiều hơn 2-3 phần tử, nếu không, hàm băm không hoạt động tốt và bạn cần thay đổi hàm băm.

Một lần nữa, tìm kiếm không phụ thuộc vào số phần tử! Chúng ta có thể sử dụng bảng băm cho bất kỳ thứ gì có kích thước khổng lồ.

Bảng băm cũng được sử dụng để tìm chuỗi và chuỗi con trong đoạn văn bản lớn bằng thuật toán Rabin Karp hoặc thuật toán Knuth-Morris-Pratt, ví dụ, rất hữu ích trong việc xác định đạo văn trong các bài báo khoa học.

Tôi nghĩ chúng ta có thể kết thúc ở đây. Trong tương lai tôi dự định xem xét các cấu trúc dữ liệu phức tạp hơn, ví dụ: cọc FibonacciCây phân đoạn. Tôi hy vọng bạn thấy hướng dẫn không chính thức này thú vị và hữu ích.

Đã dịch cho Habr bị khóa

Đề thi khoa học máy tính

Thông tin như một nguồn tài nguyên. Các phương pháp lưu trữ và xử lý thông tin.

Thông tin từ Lat. “Thông tin” có nghĩa là làm rõ, nhận thức, trình bày.

Theo nghĩa rộng thông tin -Đây là một khái niệm khoa học tổng quát bao gồm việc trao đổi thông tin giữa con người với nhau, trao đổi tín hiệu giữa thiên nhiên sống và vô tri, con người và các thiết bị.
Thông tin -Đây là thông tin về các đối tượng và hiện tượng của môi trường, các thông số, tính chất và điều kiện của chúng, làm giảm mức độ không chắc chắn và kiến ​​thức chưa đầy đủ về chúng.

Khoa học máy tính kiểm tra thông tin là thông tin, dữ liệu, khái niệm được liên kết với nhau về mặt khái niệm làm thay đổi ý tưởng của chúng ta về một hiện tượng hoặc đối tượng trong thế giới xung quanh.

Nguồn thông tin -đó là các tài liệu riêng lẻ và các mảng tài liệu riêng biệt, các tài liệu và các mảng tài liệu trong hệ thống thông tin (thư viện, kho lưu trữ, quỹ, ngân hàng).
Để thông tin được sử dụng nhiều lần, nó phải được lưu trữ.

Lưu trữ dữ liệu -đó là một cách phổ biến thông tin trong không gian và thời gian. Phương pháp lưu trữ thông tin phụ thuộc vào phương tiện của nó (sách - thư viện, tranh - bảo tàng, ảnh - album). Máy tính được thiết kế để lưu trữ thông tin nhỏ gọn với khả năng truy cập nhanh chóng.
Xử lí dữ liệu là sự chuyển đổi thông tin từ loại này sang loại khác.
Xử lý thông tin - chính quá trình chuyển đổi từ dữ liệu ban đầu sang kết quả là quá trình xử lý. Đối tượng hoặc chủ thể thực hiện việc xử lý là người thực hiện việc xử lý đó.
Kiểu xử lý thứ nhất: xử lý gắn liền với việc thu nhận thông tin mới, nội dung kiến ​​thức mới.
Kiểu xử lý thứ 2: xử lý liên quan đến thay đổi về hình thức nhưng không thay đổi nội dung (ví dụ:
dịch văn bản từ ngôn ngữ này sang ngôn ngữ khác).

Một loại xử lý quan trọng là mã hóa- chuyển đổi thông tin thành dạng biểu tượng,
thuận tiện cho việc lưu trữ, truyền tải, xử lý. Một loại xử lý thông tin khác là cấu trúc dữ liệu (nhập một thứ tự nhất định vào việc lưu trữ thông tin, phân loại, lập danh mục dữ liệu).
Một loại xử lý thông tin khác là tìm kiếm trong một số kho lưu trữ thông tin để tìm dữ liệu cần thiết đáp ứng các điều kiện tìm kiếm nhất định (truy vấn).



Khái niệm về dữ liệu có cấu trúc. Định nghĩa và mục đích của cơ sở dữ liệu

Khi tạo cơ sở dữ liệu, người dùng cố gắng sắp xếp thông tin theo nhiều đặc điểm khác nhau và nhanh chóng truy xuất một mẫu có sự kết hợp các đặc điểm tùy ý. Điều này chỉ có thể được thực hiện nếu dữ liệu được cấu trúc.

Cấu trúc -đó là sự giới thiệu các quy ước về cách trình bày dữ liệu.

Dữ liệu có cấu trúc -đó là dữ liệu được sắp xếp.

Dữ liệu phi cấu trúc –đây là dữ liệu được ghi lại, ví dụ, trong một tệp văn bản: Hồ sơ cá nhân số 1 Oleg Ivanovich Sidorov, ngày sinh. 14/11/92, Hồ sơ cá nhân số 2 Petrova Anna Viktorovna, ngày sinh. 15/03/91.

Để tự động hóa việc tìm kiếm và hệ thống hóa dữ liệu này, cần phải xây dựng các thỏa thuận nhất định về cách cung cấp dữ liệu, tức là ngày sinh phải được viết ra theo cùng một cách đối với mỗi học sinh, nó phải có cùng độ dài và định nghĩa. đặt giữa các thông tin còn lại. Nhận xét tương tự cũng áp dụng cho phần còn lại của dữ liệu (số tệp cá nhân, F., I., O.) Sau khi thực hiện cấu trúc thông tin đơn giản, nó sẽ trông như thế này:

Ví dụ về dữ liệu có cấu trúc: STT Họ và tên Ngày sinh

1 Sidorov Oleg Ivanovich 14/11/92

Các phần tử dữ liệu có cấu trúc:

1) A – trường (cột) – là đơn vị cơ bản không thể chia cắt của tổ chức thông tin

2) B – bản ghi (dòng) là tập hợp các trường có liên quan logic

3) B – bảng (file) là tập hợp các thể hiện của các bản ghi có cùng cấu trúc.

Cơ sở dữ liệu -Đây là tập hợp các dữ liệu có cấu trúc được kết nối với nhau được tổ chức trên phương tiện máy tính, chứa thông tin về các thực thể khác nhau của một lĩnh vực chủ đề nhất định (đối tượng, quy trình, sự kiện, hiện tượng).

Theo nghĩa rộng của từ này, cơ sở dữ liệu là tập hợp thông tin về các đối tượng cụ thể của thế giới thực trong bất kỳ lĩnh vực chủ đề nào.

Theo lĩnh vực chủ đềđược hiểu là một phần của thế giới thực, là đối tượng nghiên cứu để tổ chức quản lý, tự động hóa, ví dụ như một doanh nghiệp, một trường đại học, v.v.

Mục đích cơ sở dữ liệu:

1) Kiểm soát dự phòng dữ liệu. Như đã đề cập, hệ thống tệp truyền thống lãng phí bộ nhớ ngoài bằng cách lưu trữ cùng một dữ liệu trong nhiều tệp. Ngược lại, việc sử dụng cơ sở dữ liệu sẽ cố gắng loại bỏ sự dư thừa dữ liệu bằng cách tích hợp các tệp để tránh lưu trữ nhiều bản sao của cùng một thông tin.

2) Tính nhất quán của dữ liệu. Loại bỏ hoặc kiểm soát sự dư thừa dữ liệu giúp giảm nguy cơ xảy ra các điều kiện không nhất quán. Nếu một phần tử dữ liệu chỉ được lưu trữ trong cơ sở dữ liệu trong một phiên bản thì việc thay đổi giá trị của nó sẽ chỉ yêu cầu một thao tác cập nhật và giá trị mới sẽ có sẵn ngay lập tức cho tất cả người dùng cơ sở dữ liệu. Và nếu phần tử dữ liệu này, với kiến ​​​​thức về hệ thống, được lưu trữ trong cơ sở dữ liệu thành nhiều bản sao, thì hệ thống như vậy sẽ có thể đảm bảo rằng các bản sao không mâu thuẫn với nhau.

3) Chia sẻ dữ liệu. Các tập tin thường thuộc sở hữu của các cá nhân hoặc toàn bộ bộ phận sử dụng chúng trong công việc của họ. Đồng thời, cơ sở dữ liệu thuộc về toàn bộ tổ chức và có thể được chia sẻ bởi tất cả người dùng đã đăng ký. Với cách tổ chức công việc này, nhiều người dùng hơn có thể làm việc với lượng dữ liệu lớn hơn. Hơn nữa, bạn có thể tạo các ứng dụng mới dựa trên thông tin đã tồn tại trong cơ sở dữ liệu và chỉ thêm dữ liệu hiện không được lưu trữ trong đó, thay vì xác định lại các yêu cầu đối với tất cả dữ liệu mà ứng dụng mới cần.

4) Duy trì tính toàn vẹn dữ liệu. Tính toàn vẹn của cơ sở dữ liệu có nghĩa là tính chính xác và nhất quán của dữ liệu được lưu trữ trong đó. Tính toàn vẹn thường được mô tả dưới dạng các ràng buộc, tức là các quy tắc để duy trì tính nhất quán không được vi phạm trong cơ sở dữ liệu. Các ràng buộc có thể được áp dụng cho các thành phần dữ liệu trong một bản ghi hoặc cho các mối quan hệ giữa các bản ghi. Ví dụ: một ràng buộc về tính toàn vẹn có thể quy định rằng mức lương của nhân viên không được vượt quá 40.000 rúp mỗi năm hoặc trong bản ghi dữ liệu của nhân viên, số phòng ban mà anh ta làm việc phải tương ứng với một phòng ban thực tế của công ty.

5) Tăng cường bảo mật. Bảo mật cơ sở dữ liệu là bảo vệ cơ sở dữ liệu khỏi sự truy cập trái phép của người dùng. Nếu không có các biện pháp bảo mật thích hợp, dữ liệu tích hợp sẽ dễ bị tổn thương hơn dữ liệu trong hệ thống tệp. Tuy nhiên, việc tích hợp cho phép bạn xác định hệ thống bảo mật cơ sở dữ liệu cần thiết và DBMS để triển khai nó. Hệ thống bảo mật có thể được thể hiện dưới dạng tên đăng nhập và mật khẩu để xác định người dùng đã đăng ký trong cơ sở dữ liệu này. Quyền truy cập vào dữ liệu của người dùng đã đăng ký chỉ có thể bị giới hạn ở một số thao tác nhất định (trích xuất, chèn, cập nhật và xóa).