Khái niệm danh sách liên kết đôi: Khái niệm: Danh sách liên kết đôi Doubly Linked List là một biến thể của danh sách liên kết Linked List, trong đó hoạt động duyệt qua các nút có thể đư
Trang 1BỘ GIÁO DỤC VÀ ĐÀO TẠO ĐẠI HỌC KINH TẾ TP HỒ CHÍ MINH (UEH)
TRƯỜNG CÔNG NGHỆ VÀ THIẾT KẾ
ĐỒ ÁN MÔN HỌC
ĐỀ TÀI ỨNG DỤNG LINKED LIST TRONG QUẢN LÝ PLAYLIST NHẠC
Học Phần: Cấu Trúc Dữ Liệu & Giải Thuật Danh Sách Nhóm:
Giảng Viên: TS Đặng Ngọc Hoàng Thành
TP Hồ Chí Minh, Ngày 10 tháng 12 năm 2023
Trang 21.2 Cài đặt và cấu trúc Lớp Playlist 4
1.3 Các Chức Năng Trên Lớp Playlist 8
CHƯƠNG 2 ỨNG DỤNG CỦA DOUBLY LINKED LIST TRONG QUẢN LÝ PLAYLIST NHẠC 10
2.1 Giới Thiệu Ứng Dụng Playlist 10
2.2 Các Chức Năng Của Ứng Dụng Playlist 10
2.3 Hướng Dẫn Sử Dụng Ứng Dụng Playlist 16
CHƯƠNG 3 THIẾT KẾ GIAO DIỆN 18
3.1 Giao Diện Chính 18
3.2 Chi tiết chức năng 18
A Hiển Thị Danh Sách Bài Hát 18
B Cụm Điều Khiển Phát Nhạc 19
C Hộp Thoại Open File 20
D Controls Panel bên trái 20
Nhiệm vụ của các thành viên 24
TÀI LIỆU THAM KHẢO 25
Trang 32
CHƯƠNG 1 PHÂN TÍCH VÀ THIẾT KẾ LỚP DOUBLY LINKED LIST 1.1 Các khái niệm
A Khái niệm danh sách liên kết:
Mỗi danh sách liên kết được cấu tạo từ các phần tử được gọi là các nút Mỗi một nút gồm có hai phần: phần dữ liệu và phần thông tin liên kết Mỗi danh sách liên kết luôn có một nút đầu (header) để chỉ định vị trí đầu tiên của danh sách
B Phân loại danh sách liên kết:
Có 2 loại danh sách liên kết cơ bản: danh sách liên kết đơn và danh sách liên kết kép Danh sách liên kết đơn: phần liên kết (link) chứa thông tin của nút tiếp theo Danh sách liên kết kép: phần liên kết chứa thông tin của nút trước (flink) và nút sau (blink)
C Khái niệm danh sách liên kết đôi:
Khái niệm: Danh sách liên kết đôi (Doubly Linked List) là một biến thể của danh sách liên kết (Linked List), trong đó hoạt động duyệt qua các nút có thể được thực hiện theo hai chiều: về trước và về sau một cách dễ dàng khi so sánh với Danh sách liên kết đơn
Cấu trúc của Node:
Node chứa 3 thông tin: dữ liệu cần lưu trữ ở nốt, thông tin về Node phía trước, thông tin về Node phía sau
Sơ đồ 1.2.a-1 Cấu trúc của một Node
Cấu trúc của Danh sách liên kết đôi:
Danh sách liên kết đôi là tập hợp các Node, mỗi Node nắm giữ dữ liệu và liên kết với các Node phía trước và phía sau chúng tạo thành một danh sách có trình tự
Trang 43 Sơ đồ 1.2.a-2 Cấu trúc của Danh sách liên kết đôi
Sơ đồ trên, sử dụng Head, Tail có kiểu dữ liệu là Node để trỏ tới phần đầu và đuôi của danh sách liên kết Node đầu tiên, Prev trỏ tới null, Node cuối cùng, Next trỏ tới null vì không có Node nào đứng trước, đứng sau nó
D Các thuật toán cơ bản trên danh sách liên kết đôi:
a Thêm một phần tử vào cuối danh sách Add():
● Nếu danh sách đang trống và thêm một nốt mới vào danh sách thì HeadNode, TailNode, đều trỏ tới nốt mới này
● Ngược lại, nốt mới sẽ được thêm vào vị trí cuối của danh sách Đầu tiên tạo một nốt mới, với liên kết Previous trỏ tới TailNode, liên kết Next của TailNode sẽ trỏ tới nốt mới, cuối cùng cập nhật lại TailNode, TailNode sẽ trỏ tới nốt mới này
Chèn một phần tử vào một vị trí bất kỳ trong danh sách Insert():
Lưu ý: vị trí mà ta muốn chèn vào danh sách phải có giá trị hợp lệ là từ 0 đến Count ● Trường hợp chèn vào vị trí đầu tiên của danh sách: Trường hợp danh sách trống thì
HeadNode, TailNode, đều trỏ tới nốt mới này Còn không, tạo nốt mới, với liên kết Next trỏ tới HeadNode, liên kết Previous của HeadNode sẽ trỏ tới nốt mới, cuối cùng cập nhật lại HeadNode, HeadNode trỏ tới nốt mới vừa được tạo
● Trường hợp chèn vào vị trí cuối cùng của danh sách: Thực hiện như phương thức Add()
● Trường hợp còn lại: Tạo nốt mới, tìm kiếm nốt liền trước của vị trí muốn chèn vào, sử dụng phương thức tìm kiếm nốt Find(vị trí muốn chèn - 1), nốt vừa tìm kiếm được sau đây gọi là ANode, liên kết Next của ANode là phần còn lại của danh sách liên kết gọi là BNode Liên kết Next của ANode trỏ tới nốt mới, liên kết Previous của BNode trỏ tới nốt mới Cuối cùng thiết lặp liên kết của nốt mới với các nốt xung quanh, liên kết Previous trỏ tới ANode, liên kết Next trỏ tới BNode
Xóa một phần tử bất kỳ trong danh sách Remove():
Lưu ý: chỉ số của phần tử muốn xoá phải có giá trị hợp hệ là từ 0 đến Count - 1.● Trường hợp xoá phần tử đầu tiên của danh sách: Nếu danh sách chỉ còn lại một phần
tử, thì thiết đặt HeadNode, TailNode về rỗng Ngược lại, HeadNode sẽ trỏ tới nốt tiếp theo của nó, xoá liên kết Previous của HeadNode đặt về giá trị null
Trang 54 ●
● Trường hợp xoá phần tử cuối cùng của danh sách: TailNode sẽ trỏ tới nốt liền trước của nó, xoá bỏ liên kết Next của TailNode đặt về giá trị null
● Trường hợp còn lại: Tìm kiếm nốt liền trước của nốt muốn xoá bằng Find(vị trí nốt muốn xoá - 1) sau đây gọi là ANode, nốt liền sau của nốt muốn xoá gọi là BNode cũng là phần còn lại của danh sách liên kết Đặt liên kết Next của ANode trỏ tới BNode, vậy là nốt cần xoá không còn trong danh sách liên kết
1.2 Cài đặt và cấu trúc Lớp Playlist
A Cài đặt lớp Playlist
Lớp Playlist, một số thành phần cơ bản: public class PlaylistNode {
public string FileName ; public PlaylistNode Next , Previous ; public PlaylistNode ()
{ this FileName = null; this Next = null; this Previous = null; }
} public class Playlist {
private WaveOut PlayerDevice ; private AudioFileReader FileReader ; private PlaylistNode HeadNode , TailNode ; public PlaylistNode CurrentNode ; public int Count { private set ; get ; } public Playlist ()
{ this HeadNode = null; this TailNode = null; this CurrentNode = null; this Count ; = 0 StopAndDisposePlayerDevice (); }
public PlaylistNode Find (int Index ) {
PlaylistNode FindNode = HeadNode ; for (int i = 0 ; i < Index ; i ++ ) FindNode FindNode Next ;
Trang 65 }
public void Add (string NewFile ) {
PlaylistNode NewNode = new PlaylistNode { FileName NewFile }; if ( HeadNode == null)
{ HeadNode = NewNode ; TailNode = NewNode ; CurrentNode = NewNode ; }
else { TailNode Next = NewNode ; NewNode Previous = TailNode ; TailNode = NewNode ; }
this Count ++ ; }
public void Insert (string File , int Index ) {
PlaylistNode NewNode = new PlaylistNode { FileName File }; if ( Index == ) 0
if ( HeadNode == null) {
HeadNode = NewNode ; TailNode = NewNode ; }
else { NewNode Next = HeadNode ; HeadNode Previous = NewNode ; HeadNode = NewNode ; }
else if ( Index == Count ) {
TailNode Next = NewNode ; NewNode Previous = TailNode ; TailNode = NewNode ; }
else
Trang 76 PlaylistNode FindNode = Find ( Index 1 );
PlaylistNode TheRest = FindNode Next ; TheRest Previous = NewNode ; FindNode Next = NewNode ; NewNode Previous = FindNode ; NewNode Next = TheRest ; }
Count ++ ; }
public void Remove (int Index ) {
if ( Index == ) 0 {
if (this Count == ) 1 {
HeadNode = null; TailNode = null; }
else { HeadNode = HeadNode Next ; HeadNode Previous = null; }
} else if ( Index == Count ) 1 {
TailNode = TailNode Previous ; TailNode Next = null; }
else { PlaylistNode FindNode = Find ( Index 1 ); PlaylistNode TheRest = FindNode Next Next ; FindNode Next = TheRest ;
} Count ; }
public void StopAndDisposePlayerDevice () {
if ( PlayerDevice != null)
Trang 87 PlayerDevice Stop ();
PlayerDevice Dispose (); PlayerDevice = null; }
if ( FileReader != null) {
FileReader Dispose (); FileReader = null; }
} public void PrepareToPlay () {
StopAndDisposePlayerDevice (); FileReader = new AudioFileReader ( CurrentNode FileName ); PlayerDevice = new WaveOut ();
PlayerDevice Init ( FileReader ); }
public void Play () {
if ( PlayerDevice == null || FileReader == null) {
PrepareToPlay (); PlayerDevice ? Play (); }
PlayerDevice ? Play (); }
public void Pause () {
if ( FileReader != null) PlayerDevice ? Pause (); }
public void NextFile () {
if ( CurrentNode ? Next != null ) CurrentNode CurrentNode Next ; PrepareToPlay ();
PlayerDevice ? Play (); }
public void PreviousFile ()
Trang 98 if ( CurrentNode ? Previous != null)
CurrentNode = CurrentNode Previous ; PrepareToPlay ();
PlayerDevice ? Play (); }
public void ChooseFile (int Index ) {
CurrentNode = Find ( Index ); PrepareToPlay (); }
}
B Cấu trúc lớp Playlist
Playlist được xây dựng dựa trên cấu trúc của danh sách liên kết đôi, được tích hợp thêm thiết bị phát các tệp âm thanh Lớp có thể lựa chọn phát một tệp âm thanh trong một thư mục với các chức năng cơ bản: phát tệp âm thanh hiện tại, phát tệp âm thanh kế tiếp, tệp âm thanh kế trước được lưu trong liên kết của Node trong danh sách liên kết đôi
1.3 Các Chức Năng Trên Lớp Playlist
Lớp Playlist có các chức năng cơ bản của một danh sách liên kết đôi, thêm, chèn, xoá phần tử Ngoài ra còn có thêm các chức năng của một thiết bị phát âm thanh:
● Thiết bị đọc tệp âm thanh đến từ lớp AudioFileReader: FileReader ● Thiết bị phát âm thanh lớp WaveOut: PlayerDevice
● Điều chỉnh âm lượng phát ra từ việc điều chỉnh Volume (int), phạm vi 0-100 ● Điều chỉnh vị trí phát của một tệp âm thanh từ CurrentTime (int), đơn vị giây ● Khả năng tạm dừng, phát lại bài hát qua Play(), Pause()
● Chọn bài hát tiếp theo Next(), bài hát trước Previous(), chọn một bài hát cụ thể thông qua chỉ số ChooseFile(int Index)
● Một số phương thức tiện ích: PrepareToPlay() phương thức này dùng để chuẩn bị, đưa tệp vào trạng thái sẵn sàng để phát, StopAndDisposePlayerDevice() dùng để giải phóng tài nguyên, tệp mà lớp này đang sử dụng, phương thức kiểm tra một tệp có khả năng phát được âm thanh không CanPlayAudio(string FileName) để trước khi thêm tệp đó vào Playlist, ValidIndex(int Index) phương thức kiểm tra một chỉ số phần tử muốn truy cập trong Playlist có hợp lệ hay không, phương thức tìm kiếm Node trong Playlist bằng chỉ số Find(int Index), phương thức tìm kiếm vị trí của một File trong Playlist FindIndex(string Find)
● Một số thuộc tính thông tin, điều khiển các control ngoài lớp: IsPlaying để cho biết Playlist có đang phát âm thanh hay không, AutoNext chức năng tự động phát tệp kế tiếp khi đã phát hết tệp hiện tại, Repeating chức năng tự động lặp lại tệp, sự kiện
Trang 109 Tick để kích hoạt thanh trượt bài hát, sự kiện NewFileAudio cho biết khi nào Playlist bắt đầu phát một tệp âm thanh mới, sự kiện FinishPlayingFile để chương trình biết được thời điểm làm các công việc khi một tệp đã phát xong
Trang 1110
CHƯƠNG 2 ỨNG DỤNG CỦA DOUBLY LINKED LIST
TRONG QUẢN LÝ PLAYLIST NHẠC 2.1 Giới Thiệu Ứng Dụng Playlist
Ứng dụng Playlist là một ứng dụng quản lý danh sách phát nhạc được xây dựng dựa trên cấu trúc dữ liệu Doubly Linked List Được thiết kế để cung cấp một giao diện đơn giản và thuận tiện cho người dùng để quản lý và phát các bài hát, Doubly Linked List được áp dụng trong việc quản lý danh sách bài hát, mỗi nút của nó chứa thông tin về một bài hát cùng với tham chiếu tới bài hát trước và sau Điều này mang lại nhiều lợi ích, cho phép việc thêm, xóa, hoặc di chuyển qua lại giữa các bài hát một cách nhanh chóng và linh hoạt Ngoài ra, trong ứng dụng còn tích hợp các tính năng tìm kiếm nhạc, chèn hình ảnh giúp người dùng có được những trải nghiệm tốt nhất
2.2 Các Chức Năng Của Ứng Dụng Playlist
Ứng dụng Playlist cung cấp các chức năng sau:
A Thêm và Xóa Bài Hát
Người dùng có thể thêm mới các bài hát vào danh sách phát và cũng có thể xóa bỏ các bài hát không cần thiết từ danh sách
private void OpenFile_Click ( object sender, EventArgs ) {
OpenFileDialog OpenFile = new OpenFileDialog () {
Filter = "MP3 Files (*.mp3)|*.mp3" , Multiselect = true ,
Title = "Open Music Files"
}; if OpenFile ShowDialog () == DialogResult.OK) {
List < string > AddNewFiles = MusicList.MusicFiles ToList (); AddNewFiles AddRange (OpenFile.FileNames);
MusicList.MusicFiles = AddNewFiles ToArray (); foreach ( string FileName in OpenFile.FileNames) {
if !File Exists (Path Combine (MusicList DirectoryPath Path GetFileName ( FileName ))))
File Copy (FileName , Path Combine ( MusicList DirectoryPath Path , GetFileName (FileName))); }
PlayMusicList Dispose (); ResetProperties (); }
Trang 1211
B Hiển Thị Thông Tin Bài Hát
Người dùng có thể xem thông tin chi tiết về bài hát đang được phát, bao gồm thời lượng, tên bài hát, và hình ảnh liên quan nếu có
if ( Trash != null ) this Trash Visible false ;
this Controls Clear ();
if ( MusicFiles Length ) > 0
for (int i = 0 ; i < MusicFiles Length ; i ++ )
if ( File Exists ( MusicFiles [ ]))
{
Panel MusicPanel = new Panel ();
PictureBox ImageMusic = new PictureBox ();
PictureBox PlayButton = new PictureBox ();
Label MusicName = new Label ();
Label TotalTime = new Label ();
//
// ImageMusic Name = "ImageMusic" ;
Trang 1312 ImageMusic SizeMode = PictureBoxSizeMode Zoom ;
ImageMusic Tag = MusicFiles [ ]; if ( File Exists ( Path Combine ( FilesPath ,
ImageMusic Image = Image FromFile ( Path Combine ( FilesPath ,
else ImageMusic Image ( = this Parent as dynamic) Icon ToBitmap ();
ImageMusic MouseClick += ImageMusic_RightClick ; //
// Nút PlayPause //
PlayButton Name = "PlayButton" ; PlayButton Size = new Size ( 20 , 20 );
PlayButton Cursor = Cursors Hand ; PlayButton SizeMode = PictureBoxSizeMode Zoom ; if ( PlayerDevice CurrentNode FileName == MusicFiles [ ] && PlayerDevice IsPlaying )
PlayButton Image = Properties Resources PauseThis ; else
PlayButton Image = Properties Resources PlayThis ; PlayButton Tag = false; // true là đang phát, false là dừng PlayButton Click += ( sender , e ) => PlayButton_Click ((( sender as PictureBox ) Parent as dynamic ) Name );
// // Tên bài hát //