Vui Chơi Với Thuật Toán Đệ Quy Trong Lập Trình Với Excel

Liên hệ QC

Kiều Mạnh

I don't program, I beat code into submission!!!
Tham gia
9/6/12
Bài viết
5,541
Được thích
4,125
Giới tính
Nam
Tình hình là mấy ngày nay Mình đang nghiên cứu ứng dụng thuật Toán đệ Quy trong VBA một tí ...Có đọc rất nhiều bài trên GPE và Goolge để nghiên cứu xem tình hình sao...

Thấy bài trên GPE rất nhiều nhưng ứng dụng và bài viết cũng ít ...

Mình có nghiên cứu nhưng chưa thật sự hiểu sâu lắm về thuật Toán đệ quy lắm....Vây Mình lập ra đề tài này để mình học hỏi và nghiên cứu thêm ...

Nếu Bạn nào có hứng với thuật Toán đệ quy và có thắc mắc gì thì cứ úp Bài chung vào đây càng nhiều càng tốt ta cùng nhau vui chơi cho thỏa thích...--=0

Mạnh là nông dân thuần túy thích thì vọc chơi nên thuật ngữ chuyên nghành về lập trình phát biểu không giống ai ... Mong các Bạn có Kiến thức Hàm lâm chỉ thêm chứ không nên bắt bẻ nọ kia ...xin cảm ơn

Sẽ có nhiều bài ứng dụng thuật toán đệ quy trong Thớt này ...từ từ ta cùng nhau ngâm cứu

Ứng dụng duyệt File trong Folder và SubFolders Open File
Mã:
Public Sub OpenFilesInSubFolder(ByVal sFolder As String, ByVal InSub As Boolean)
    Dim objsFolder As Object, ObjFile As Object
    With CreateObject("Scripting.FileSystemObject")
        For Each ObjFile In .GetFolder(sFolder).Files
            If .GetExtensionName(ObjFile) Like "xls*" Then
                If Left(ObjFile.Name, 2) <> "~$" Then
                    If ObjFile.Name <> ThisWorkbook.Name Then
                        With Workbooks.Open(ObjFile)
                            .Close False
                        End With
                    End If
                End If
            End If
        Next ObjFile
        If InSub Then
            For Each objsFolder In .GetFolder(sFolder).subFolders
                Call OpenFilesInSubFolder(objsFolder.Path, True)
            Next objsFolder
        End If
    End With
End Sub


''False = Open File Trong Folder       ==> không đệ Quy
''True = Open File Trong SubFolders ==> Đệ Quy


Public Sub Main()
    Dim Path As String
    Path = ThisWorkbook.Path
    OpenFilesInSubFolder Path, True
End Sub

Với code trên nếu Sub Main mà là False thì sẻ mở hết tất cả các File Excel trong Folder đó ...Còn True thì sẻ mở hết Từ Folder cha, con, cháu ... trong Folder cha...

Nếu Các Bạn có cách nào viết khác xin được chỉ thêm....

Rất mong các Bạn tham gia xem cách Viết như vậy có vấn đề gì không...
Nếu Ok bài sau ta sẻ ứng dụng nó tổng hợp các File trong Folder cha, con, cháu chắt nhà nó....

Sau nữa thì ta chơi qua ADO....
.................................
Xin cảm ơn Các bạn đã tham gia

Chúc Vui Chơi Trí Tuệ , Hòa Bình & Vui Vẻ

Thân
 
Lần chỉnh sửa cuối:
Kiêu Mạnh còn rất thanh niên đấy nhá (có thể già lão nhưng tính cách thanh niên như tớ) ... quan trọng là mình giải thích được cách làm của mình. Kiến thức là trừu tượng, khái niệm cũng như vậy. Bạn có thể tự định nghĩa một khái niệm cho riêng mình, đâu cần cứ nhất thiết phải có ai đó cùng đưa ra quan điểm về nhận định đó của bạn.
Cộng đồng là nơi chia sẻ và cũng là nơi những ý kiến nhỏ trở thành phát kiến lớn....
(Bài toán Tháp Hà nội là một ví dụ kinh điển theo kiểu đó)
Chúc các bạn vui vẻ!

Đọc thêm về Đệ quy
http://www.cs.utah.edu/~germain/PPS/Topics/recursion.html
https://en.wikipedia.org/wiki/Recursion_(computer_science)
http://www.cs.odu.edu/~cs381/cs381content/recursive_alg/rec_alg.html

Định nghĩa tạm gọi là thông dụng của Đệ quy trong Thuật toán và khoa học máy tính thế này:
Thuật toán:
Thuật toán đệ quy là thuật toán tự gọi chính nó với giá trị đầu vào "nhỏ hơn hoặc đơn giản hơn" theo đó trả về kết quả tính toán của giá trị đầu vào bằng cách thức đơn giản đối với giá trị trả về của giá trị đầu vào nhở hơn đó. Nói chung, nếu một vấn đề có thể giải quyết bằng cách áp dụng cùng phương pháp đối với các giá trị đầu vào nhỏ hơn theo đó việc giảm dần tính phức tạp của giá trị đầu vào sẽ giải quyết được bài toán thì người ta gọi đó là Đệ quy.


Nói khác hơn Đệ quy trong lập trình là việc MỘT THỦ TỤC/HÀM GỌI LẠI CHÍNH NÓ để thực hiện việc gì đó.
Việc sử dụng lặp hay không lặp đó chỉ là tiểu tiết các bước xử lý trong chương trình mà không phải là biện pháp của ĐỆ QUY.


Và hiện đang có hàng ngàn cách định nghĩa khác nhau đối với đệ quy.
 
Lần chỉnh sửa cuối:
Upvote 0
Kiêu manh còn rất thanh niên đấy nhá... quan trọng là mình giải thích được cách làm của mình. Kiến thức là trừu tượng, khái niệm cũng như vậy. Bạn có thể tự định nghĩa một khái niệm cho riêng mình, đâu cần cứ nhất thiết phải có ai đó cùng đưa ra quan điểm về nhận định đó của bạn.
Cộng đồng là nơi chia sẻ và cũng là nơi những ý kiến nhỏ trở thành phát kiến lớn....
(Bài toán Tháp Hà nội là một ví dụ kinh điển theo kiểu đó)
Chúc các bạn vui vẻ!
OK ...Mạnh hiểu ý Bạn mà....Câu trả lời Rất hay....Lách một cách tài tình...

Kiều Mạnh là một Lão nông thuần túy mà ....Còn đâu nữa mà thanh niên chứ ...,,,,,,,{}{}{

Cảm ơn Bạn
 
Upvote 0
Bạn hiền:
---------
Mới xem file #37 của anh QuangHai rất chi là hay:

Tham số trong mảng: SortOrder = Array(2 3) của anh ấy là sort theo 2 cột, ưu cột 2, rồi đến cột 3

Nếu đổi ngược lại SortOrder = Array(3, 2): thì nó ưu tiên sort cột 3 trước, và sort lại cột 2 theo cột 3...

Và nếu thêm tham số vào tiếp trong mảng trên: SortOrder = Array(3, 2,1,6,5,...) thì nó cứ ưu tiên cái đầu tiên,...và kế tiếp, sort kế tiếp...

=> Code này của anh Quang Hải ứng dụng rất tốt trong việc Sort nhiều cột trên mảng Ảo...: Ôi thần linh ơi...

Và chú ý hơn là: trên mảng ảo... anh ấy thêm 1 cột cuối cùng, nối mảng vào đây. Và sort cột này...hic hic....-\\/.-\\/.-\\/.
nếu bạn muốn quan tâm về các kỹ thuật sort, thì tìm hiểu mười mấy cách sort trong kỹ thuật lập trình, cách của anh hải là 1 trong mười mấy cách đó, thường làm việc với excel nó có sẳn hết nên những cách sort này bị lãng quên theo thời gian
ở đây có bàn về một số sort những đã bị lãng quên
http://www.giaiphapexcel.com/forum/showthread.php?98887-Một-số-thuật-toán-về-sort-mảng
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn hiền:
---------
Mới xem file #37 của anh QuangHai rất chi là hay:

Tham số trong mảng: SortOrder = Array(2 3) của anh ấy là sort theo 2 cột, ưu cột 2, rồi đến cột 3

Nếu đổi ngược lại SortOrder = Array(3, 2): thì nó ưu tiên sort cột 3 trước, và sort lại cột 2 theo cột 3...

Và nếu thêm tham số vào tiếp trong mảng trên: SortOrder = Array(3, 2,1,6,5,...) thì nó cứ ưu tiên cái đầu tiên,...và kế tiếp, sort kế tiếp...

=> Code này của anh Quang Hải ứng dụng rất tốt trong việc Sort nhiều cột trên mảng Ảo...: Ôi thần linh ơi...

Và chú ý hơn là: trên mảng ảo... anh ấy thêm 1 cột cuối cùng, nối mảng vào đây. Và sort cột này...hic hic....-\\/.-\\/.-\\/.
Bạn Hiền của Mạnh ơi ....Code đó Anh Hải Copy cho Mạnh lâu lắm rồi ...Code đó thần linh mà
 
Upvote 0
OK ...Mạnh hiểu ý Bạn mà....Câu trả lời Rất hay....Lách một cách tài tình...

Kiều Mạnh là một Lão nông thuần túy mà ....Còn đâu nữa mà thanh niên chứ ...,,,,,,,{}{}{

Cảm ơn Bạn

anh Paulsteigel chắc thuộc thế hệ chú bác của mình , nên anh ấy dùng chữ "còn thanh niên quá"
chứ như mình là phang ngay câu : "còn trẻ trâu quá" . ha hahahahahaha
Đối với mình thì ai thích nói câu gì cũng được . Nhưng phải chứng minh được mình nói đúng bằng hành động cụ thể .
Chẳng hạn như
Gợi ý chơi thôi nha, Trong sub ở trên nếu đã sử dụng đệ quy thì sẽ không có vòng lặp làm gì. đệ quy là gì? chẳng qua là quay lại làm y chang với cái thằng cha sinh ra nó thôi

mình vẫn chưa nhìn thấy bài viết nào viết lại #1 mà bỏ hết các vòng lặp . Nên mình không tin tưởng , thông cảm mình chỉ tin vào cái gì mình thấy cụ thể , đó là lời thật lòng chứ không chỉ trích ai hết .
 
Upvote 0
anh Paulsteigel chắc thuộc thế hệ chú bác của mình , nên anh ấy dùng chữ "còn thanh niên quá"
chứ như mình là phang ngay câu : "còn trẻ trâu quá" . ha hahahahahaha
Đối với mình thì ai thích nói câu gì cũng được . Nhưng phải chứng minh được mình nói đúng bằng hành động cụ thể .
Chẳng hạn như


mình vẫn chưa nhìn thấy bài viết nào viết lại #1 mà bỏ hết các vòng lặp . Nên mình không tin tưởng , thông cảm mình chỉ tin vào cái gì mình thấy cụ thể , đó là lời thật lòng chứ không chỉ trích ai hết .
mình thì khác nha, ai nói gì làm gì cũng ok, thích thì làm không thì thôi, cũng chẳng cần ai đánh giá này nọ, chỉ cần xếp đánh giá và trả lương là ok rồi, còn trên diễn đàn học hỏi trao đổi vui chơi là chính, nên cũng chẳng chứng tỏ hơn thua làm gì? ai cũng có thể hơn mình mà đúng không?
 
Upvote 0
Mình cũng khoái API lắm ....Nhưng API với mình tịt toàn Tập có chăng Copy của ai đó thấy phù hợp với công việc xong độ lại một tí chơi vậy thôi chứ ....

Thật lòng phải nói ra nhưng dòng trên thấy cũng ngài ngại sao ý ...-\\/.-\\/.

Nếu được mong Bạn cho 1 code để mình học hỏi
xin cảm ơn
Đệ quy là phương pháp rất hay, nhưng khá "khó xơi". Thấy các bạn gợi ý về hàm API, mình xin góp vui ít code dùng API (không đệ quy)^^.
[GPEcode=vb]
Option Explicit


Private Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileW" (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileW" (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long


Const MAX_PATH = 255
Const FILE_ATTRIBUTE_DIRECTORY = &H10
Const FILE_ATTRIBUTE_HIDDEN = &H2
Const FILE_ATTRIBUTE_NORMAL = &H80
Const FILE_ATTRIBUTE_READONLY = &H1
Const FILE_ATTRIBUTE_SYSTEM = &H4


Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type


Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * 14
End Type


Private Sub CheckDir(sFolder As String, DirCount As Integer, fileCount As Integer)
Dim myFolder As New Collection
Dim FileData As WIN32_FIND_DATA
Dim res As Long, hFind As Long, fileName As String
Dim Sh As Worksheet, Arr(), Target As Worksheet
Set Target = Sheets("TongHop")
DirCount = 0
fileCount = 0
myFolder.Add (sFolder)


Do While (myFolder.Count)

sFolder = myFolder.Item(1)
myFolder.Remove (1)


hFind = FindFirstFile(StrConv(sFolder & "\*.*", vbUnicode), FileData)
If (hFind = -1) Then GoTo finish


Do
fileName = StripNulls(FileData.cFileName)
If (fileName <> ".") And (fileName <> "..") Then
If (FileData.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) Then
myFolder.Add (sFolder & "" & fileName)
DirCount = DirCount + 1
Else
fileCount = fileCount + 1

If Not (fileName Like "*TongHop.xlsb") Then
With Workbooks.Open(sFolder & "" & fileName)
For Each Sh In .Worksheets
If Sh.Name = "THU" Then
Arr = Sh.Range("A6", Sh.[A1000].End(3)).Resize(, 10).Value
Target.Range("A65536").End(3)(2).Resize(UBound(Arr), 10) = Arr
End If
Next
.Close False
End With
End If

End If
End If


res = FindNextFile(hFind, FileData)
Loop Until (res = 0)


finish:
FindClose (hFind)
Loop
End Sub


Function StripNulls(OriginalStr As String) As String
OriginalStr = StrConv(OriginalStr, vbFromUnicode)
If (InStr(OriginalStr, Chr(0)) > 0) Then
OriginalStr = Left(OriginalStr, InStr(OriginalStr, Chr(0)) - 1)
End If
StripNulls = OriginalStr
End Function


Private Sub Test()
Dim DirCount As Integer, fileCount As Integer
Dim Path As String
ActiveSheet.UsedRange.ClearContents
Path = ThisWorkbook.Path
CheckDir Path, DirCount, fileCount
MsgBox "Check Complete - Folder: " & DirCount & " - File: " & fileCount
End Sub


[/GPEcode]
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn hiền:
---------
Mới xem file #37 của anh QuangHai rất chi là hay:

Tham số trong mảng: SortOrder = Array(2 3) của anh ấy là sort theo 2 cột, ưu cột 2, rồi đến cột 3

Nếu đổi ngược lại SortOrder = Array(3, 2): thì nó ưu tiên sort cột 3 trước, và sort lại cột 2 theo cột 3...

Và nếu thêm tham số vào tiếp trong mảng trên: SortOrder = Array(3, 2,1,6,5,...) thì nó cứ ưu tiên cái đầu tiên,...và kế tiếp, sort kế tiếp...

=> Code này của anh Quang Hải ứng dụng rất tốt trong việc Sort nhiều cột trên mảng Ảo...: Ôi thần linh ơi...

Và chú ý hơn là: trên mảng ảo... anh ấy thêm 1 cột cuối cùng, nối mảng vào đây. Và sort cột này...hic hic....-\\/.-\\/.-\\/.
Bạn Hiền Thử code sau xem sao
Mã:
Sub ArraySort()
'Written by QuangHai
Dim Data()
Data = Array(20, 19, 18, 17, 16, 8, 14, 13, 12, 11, 10, 9)
QuickSort Data, LBound(Data), UBound(Data)
MsgBox Join(Data)
End Sub
 
Upvote 0
mình thì khác nha, ai nói gì làm gì cũng ok, thích thì làm không thì thôi, cũng chẳng cần ai đánh giá này nọ, chỉ cần xếp đánh giá và trả lương là ok rồi, còn trên diễn đàn học hỏi trao đổi vui chơi là chính, nên cũng chẳng chứng tỏ hơn thua làm gì? ai cũng có thể hơn mình mà đúng không?

ừ , nhưng mình chưa nhìn thấy cái sự học hỏi trao đổi vui chơi được thể hiện
nếu là mình mà ai đó lịch sự năn nỉ xin 1 đoạn code nhỏ bé như này
anh ơi , tụi em dốt và chậm hiểu lắm . Xin anh chiếu cố cho tụi em vài dòng code đệ quy thay thế vòng lặp ở #1 đi anh . Chứ anh nói vậy tụi em chưa có hình dung ra được . Cảm ơn anh .
thì mình không ngại gì mà từ chối cả . Vì họ đang chờ để học tập mình với sự cầu tiến
Nhưng xã hội vốn đa dạng mà , mình đâu thể đòi hỏi người khác cũng phải cư xử như mình được
Nên nếu đã từ chối giúp 1 đoạn code thì thôi mình chịu , chỉ buồn cho khẩu hiệu .......

học hỏi trao đổi vui chơi là chính
 
Upvote 0
Đề Nghị Các Bạn Thực hiện theo Tôn chỉ Mục đích Bài #1 nha..

Chúc Vui Chơi Trí Tuệ , Hòa Bình & Vui Vẻ

Thân
 
Upvote 0
Đệ quy là phương pháp rất hay, nhưng khá "khó xơi". Thấy các bạn gợi ý về hàm API, mình xin góp vui ít code dùng API (không đệ quy)^^.
[GPEcode=vb]
Option Explicit


Private Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileW" (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileW" (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long


Const MAX_PATH = 255
Const FILE_ATTRIBUTE_DIRECTORY = &H10
Const FILE_ATTRIBUTE_HIDDEN = &H2
Const FILE_ATTRIBUTE_NORMAL = &H80
Const FILE_ATTRIBUTE_READONLY = &H1
Const FILE_ATTRIBUTE_SYSTEM = &H4


Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type


Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * 14
End Type


Private Sub CheckDir(sFolder As String, DirCount As Integer, fileCount As Integer)
Dim myFolder As New Collection
Dim FileData As WIN32_FIND_DATA
Dim res As Long, hFind As Long, fileName As String
Dim Sh As Worksheet, Arr(), Target As Worksheet
Set Target = Sheets("TongHop")
DirCount = 0
fileCount = 0
myFolder.Add (sFolder)


Do While (myFolder.Count)

sFolder = myFolder.Item(1)
myFolder.Remove (1)


hFind = FindFirstFile(StrConv(sFolder & "\*.*", vbUnicode), FileData)
If (hFind = -1) Then GoTo finish


Do
fileName = StripNulls(FileData.cFileName)
If (fileName <> ".") And (fileName <> "..") Then
If (FileData.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) Then
myFolder.Add (sFolder & "" & fileName)
DirCount = DirCount + 1
Else
fileCount = fileCount + 1

If Not (fileName Like "*TongHop.xlsb") Then
With Workbooks.Open(sFolder & "" & fileName)
For Each Sh In .Worksheets
If Sh.Name = "THU" Then
Arr = Sh.Range("A6", Sh.[A1000].End(3)).Resize(, 10).Value
Target.Range("A65536").End(3)(2).Resize(UBound(Arr), 10) = Arr
End If
Next
.Close False
End With
End If

End If
End If


res = FindNextFile(hFind, FileData)
Loop Until (res = 0)


finish:
FindClose (hFind)
Loop
End Sub


Function StripNulls(OriginalStr As String) As String
OriginalStr = StrConv(OriginalStr, vbFromUnicode)
If (InStr(OriginalStr, Chr(0)) > 0) Then
OriginalStr = Left(OriginalStr, InStr(OriginalStr, Chr(0)) - 1)
End If
StripNulls = OriginalStr
End Function


Private Sub Test()
Dim DirCount As Integer, fileCount As Integer
Dim Path As String
ActiveSheet.UsedRange.ClearContents
Path = ThisWorkbook.Path
CheckDir Path, DirCount, fileCount
MsgBox "Check Complete - Folder: " & DirCount & " - File: " & fileCount
End Sub


[/GPEcode]
Hình như nó lỗi với File Tiếng Việt có dấu ...Bạn thử coi lại xem
 
Upvote 0
Mình có kiểm tra rồi, không phát sinh lỗi, bạn có thể nói rõ lỗi ở dòng code nào và lỗi ra sao không.
(trong code mình đã xử lý vấn đề liên quan Unicode)
Hình lỗi như sau...........Mình cũng không biết nữa
Mới tìm ra xong Phải Thêm
Mã:
Path = ThisWorkbook.Path [B]& "\"
...Như vậy nó lấy được cái Folder thứ nhất ...xong Folder trong Nó nữa là lỗi...Lỗi này nhỏ thôi mà

[/B]
 

File đính kèm

  • Capture.jpg
    Capture.jpg
    15 KB · Đọc: 47
Lần chỉnh sửa cuối:
Upvote 0
Mình có kiểm tra rồi, không phát sinh lỗi, bạn có thể nói rõ lỗi ở dòng code nào và lỗi ra sao không.
(trong code mình đã xử lý vấn đề liên quan Unicode)
Thêm dòng sau nữa trong CheckDir là OK tuyệt đối...Cảm ơn Bạn
Mã:
If Right(sFolder, 1) <> "\" Then sFolder = sFolder + "\"
 
Upvote 0
Thuật toán đệ quy không phải dễ ăn đâu. Dám cá trong 10 cao thủ trên diễn đàn thì hết 9 người không viết vẽ gì được nếu giao cho 1 máy tính mới tinh và buộc phải viết mọi thứ từ trong đầu lâu. Mình cũng đã từng nghiên cứu mất cả tuần, nhưng giờ nếu ngồi viết từ đầu mà không nhìn lại code cũ thì pó tay.
 
Upvote 0
Thuật toán đệ quy không phải dễ ăn đâu. Dám cá trong 10 cao thủ trên diễn đàn thì hết 9 người không viết vẽ gì được nếu giao cho 1 máy tính mới tinh và buộc phải viết mọi thứ từ trong đầu lâu. Mình cũng đã từng nghiên cứu mất cả tuần, nhưng giờ nếu ngồi viết từ đầu mà không nhìn lại code cũ thì pó tay.

Có lẽ ta nên thảo luận vui một chút về phản hồi của bác Hải để mọi người thêm tự tin khi làm việc với Đệ quy! Mạn phép bác nếu có gì lỗ mỗ nhé. Em toàn là thiện ý thôi

1. Code cũ và code mới.
... Đúng 99%
Nhiều khi các ý tưởng chỉ lóe sáng trong chốc lát sau đó không bao giờ có lại được vì thế việc tham khảo code cũ là điều đương nhiên. Em tin rằng không ai trong chúng ta mà không phải tham khảo các nguồn mã có sẵn để biên lại.
(Nếu không làm thế thì làm sao có cộng đồng mạng và GPL - mã nguồn mở)
Thêm nữa, với việc sử dụng các đoạn mã có sẵn ta tiết kiệm được rất nhiều thời gian thay vì lại phải nghĩ lại từ những bài toán cũ.
Tuy nhiên, việc bác đưa ra tình huống máy mới ... thì có lẽ cũng hơi không liên quan mấy về vấn đề thảo luận về ĐỆ QUY HÀM

2. Đệ quy khó .... chưa hợp lý lắm
Đệ quy không khó về quan điểm lý thuyết, nếu ta cho rằng nó khó bởi vì ta chưa tiếp cận nó một cách phù hợp và kín kẽ mà thôi.
Đối với nhiều người, việc tự dưng hàm này lại tự gọi nó thì ngay cả trong tưởng tượng cũng khó mà theo được - vì thế nó khó.

Lấy ví dụ về tính giai thừa
n! = 1 x 2 x .... x n
Ta sẽ thấy ngay cách giải tuần tự là đơn giản nhất
[GPECODE=vb]
Function Giaithua(n as long) as double
Dim i as Long, Ketqua as Double
For i=1 to n
Ketqua = Ketqua * i
Next
Giaithua = Ketqua
End Function
[/GPECODE]

Còn ứng dụng đệ quy thế nào?
Hãy phân tích vấn đề 1 chút
Với phép toán tính n!
+ Chỉ dừng thực hiện phép nhân khi thừa số nhỏ hơn n hoặc (nếu bất đầu thực hiện phép nhân từ 1);
+ Chỉ dừng thực hiện phép nhân khi thừa số lớn hơn 1 (nếu bắt đầu nhân từ n)
Vậy cái phép toán giống nhau đó là nhân và tham số sẽ giảm dần hoặc tăng dần.

Thế thì có thể áp dụng Đệ quy để tính giai thừa như thế này:
Cách 1 - Giảm dần
[GPECODE=vb]
Function GiaithuaNguoc(n As Long) As Double
If n = 1 Then
GiaithuaNguoc = 1
Else
GiaithuaNguoc = n * GiaithuaNguoc(n - 1)
End If
End Function[/GPECODE]
Theo cách này, phương pháp sẽ thực hiện như sau:
Khi n khác 1 thì
Giá trị giai thừa = n x kết quả của phép giai thừa với n giảm đi 1 đơn vị.
Việc tính này sẽ tích lũy cho đến khi n = 1 thì dừng lại và kết thúc phép nhân

Cách 2 - tăng dần
[GPECODE=vb]
Function GiaithuaThuan(n As Long, Optional i As Long = 1) As Double
If i < n Then
GiaithuaThuan = i * GiaithuaThuan(n, i + 1)
Else
GiaithuaThuan = n
End If
End Function[/GPECODE]

Theo cách này thì, khi biến thực hiện nhỏ hơn n
Giá trị giai thừa = biến đó x kết quả phép giai thừa với thừa số có giá trị tăng 1 đơn vị.
Việc tính này sẽ kết thúc khi biến đếm dừng lại ở giá trị n.

Muốn làm được với thuật toán đệ quy thì ta cần nắm vững quá trình tính toán theo cách của máy tính và biết được cái gì sẽ giả về và cái gì sẽ là tham số.
Như vậy em nghĩ nó sẽ đơn giản hơn rất nhiều.

Túm lại em chỉ muốn chia sẻ một cách nhìn khoan dung với Đệ quy... rất mong các bác chia sẻ thêm vài luận điểm nữa để các bạn trẻ có thể hiểu rõ và làm chủ được Đệ quy.

Và để bổ sung cho việc đơn giản hóa Đệ quy, các bạn hãy xem Video sau đây với kỹ năng dùng debug nhé. Với cách làm này mọi người sẽ hiểu hơn về đệ quy

[video]https://youtu.be/zBsad01ZyG8[/video]
 
Lần chỉnh sửa cuối:
Upvote 0
Hùa theo bài viết trên, tôi xin tặng các bạn 2 công cụ (đơn giản, thừa kế, sử dụng mã nguồn của nhiều bên và cả của tôi) để làm việc:
+ Cho phép dịch văn bản trên Word bằng công cụ Google Translate (đọc bài chi tiết ở đây). Chọn văn bản, nhấn Ctrl+Shift+E dịch Anh Việt và Ctrl+Shift+V để làm ngược lại
+ Cho phép dịch văn bản trên Excel (đọc bài chi tiết ở đây). Chọn vùng, nhấn Ctrl+Shift+E dịch Anh Việt và Ctrl+Shift+V để làm ngược lại
Sự đặc biệt của công cụ này đó là việc ứng dụng công nghệ truy vấn Web không đồng bộ (Asynchronous) với WinHttp/XmlHttp.
Nếu các bạn (doveandrose chẳng hạn) sử dụng Winhttp trong VBA thường phải để chế độ Asynchronous là False để đợi bao giờ máy chủ Web trả lời xong mới làm việc tiếp. Với 2 công cụ này, chúng ta đặt là True và bạn có thể thấy việc dịch được tiến hành đồng thời với nhiều Cell hoặc đoạn văn cùng lúc.
Template cho Word: http://www.sfdp.net/thuthuataccess/Normal.dotm?attredirects=0&d=1
Addin cho Excel: http://www.sfdp.net/thuthuataccess/Tools.xlam?attredirects=0&d=1

PS.. Xin lỗi Ban quản trị vì tôi trích dẫn bài ở trang web khác (vì ngại viết lại hoặc cắt dán, copy). Đa tạ!
Ngoài ra, xin bổ sung thêm một ứng dụng nhỏ viết bằng Access để truy cập Google Drive, tải file lên mà không cần tới InternetExplorer hoặc trình duyệt.
(Cũng là cóp nhặt, sáng kiến ...vv). Toàn văn các bài viết ở đây.
Ứng dụng ở đây: http://www.sfdp.net/thuthuataccess/demo/democAuth.rar?attredirects=0&d=1
 
Upvote 0
Hùa theo bài viết trên, tôi xin tặng các bạn 2 công cụ (đơn giản, thừa kế, sử dụng mã nguồn của nhiều bên và cả của tôi) để làm việc:
+ Cho phép dịch văn bản trên Word bằng công cụ Google Translate (đọc bài chi tiết ở đây). Chọn văn bản, nhấn Ctrl+Shift+E dịch Anh Việt và Ctrl+Shift+V để làm ngược lại
+ Cho phép dịch văn bản trên Excel (đọc bài chi tiết ở đây). Chọn vùng, nhấn Ctrl+Shift+E dịch Anh Việt và Ctrl+Shift+V để làm ngược lại
Sự đặc biệt của công cụ này đó là việc ứng dụng công nghệ truy vấn Web không đồng bộ (Asynchronous) với WinHttp/XmlHttp.
Nếu các bạn (doveandrose chẳng hạn) sử dụng Winhttp trong VBA thường phải để chế độ Asynchronous là False để đợi bao giờ máy chủ Web trả lời xong mới làm việc tiếp. Với 2 công cụ này, chúng ta đặt là True và bạn có thể thấy việc dịch được tiến hành đồng thời với nhiều Cell hoặc đoạn văn cùng lúc.
Template cho Word: http://www.sfdp.net/thuthuataccess/Normal.dotm?attredirects=0&d=1
Addin cho Excel: http://www.sfdp.net/thuthuataccess/Tools.xlam?attredirects=0&d=1

PS.. Xin lỗi Ban quản trị vì tôi trích dẫn bài ở trang web khác (vì ngại viết lại hoặc cắt dán, copy). Đa tạ!
Ngoài ra, xin bổ sung thêm một ứng dụng nhỏ viết bằng Access để truy cập Google Drive, tải file lên mà không cần tới InternetExplorer hoặc trình duyệt.
(Cũng là cóp nhặt, sáng kiến ...vv). Toàn văn các bài viết ở đây.
Ứng dụng ở đây: http://www.sfdp.net/thuthuataccess/demo/democAuth.rar?attredirects=0&d=1

trong bài viết trên có nhắc tên Doveandrose , rất cảm ơn anh có nhã ý giúp đỡ , nhưng anh làm như vậy e là không đúng khuôn khổ nội quy của diễn đàn này . Thiết nghĩ thành viên BQT nào đi ngang xin cắt bài viết từ chỗ này sang topic mới . Có nhiều cái để chúng ta bàn về gửi truy vấn bất đồng bộ như : cách tạo , sử dụng ,.... Chứ 1 cái file Addin trong Excel chắc khó để diễn tả hết .
 
Upvote 0
Đệ quy là phương pháp rất hay, nhưng khá "khó xơi". Thấy các bạn gợi ý về hàm API, mình xin góp vui ít code dùng API (không đệ quy)^^.
[GPEcode=vb]
Option Explicit


Private Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileW" (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileW" (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long


Const MAX_PATH = 255
Const FILE_ATTRIBUTE_DIRECTORY = &H10
Const FILE_ATTRIBUTE_HIDDEN = &H2
Const FILE_ATTRIBUTE_NORMAL = &H80
Const FILE_ATTRIBUTE_READONLY = &H1
Const FILE_ATTRIBUTE_SYSTEM = &H4


Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type


Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * 14
End Type


Private Sub CheckDir(sFolder As String, DirCount As Integer, fileCount As Integer)
Dim myFolder As New Collection
Dim FileData As WIN32_FIND_DATA
Dim res As Long, hFind As Long, fileName As String
Dim Sh As Worksheet, Arr(), Target As Worksheet
Set Target = Sheets("TongHop")
DirCount = 0
fileCount = 0
myFolder.Add (sFolder)


Do While (myFolder.Count)

sFolder = myFolder.Item(1)
myFolder.Remove (1)


hFind = FindFirstFile(StrConv(sFolder & "\*.*", vbUnicode), FileData)
If (hFind = -1) Then GoTo finish


Do
fileName = StripNulls(FileData.cFileName)
If (fileName <> ".") And (fileName <> "..") Then
If (FileData.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) Then
myFolder.Add (sFolder & "" & fileName)
DirCount = DirCount + 1
Else
fileCount = fileCount + 1

If Not (fileName Like "*TongHop.xlsb") Then
With Workbooks.Open(sFolder & "" & fileName)
For Each Sh In .Worksheets
If Sh.Name = "THU" Then
Arr = Sh.Range("A6", Sh.[A1000].End(3)).Resize(, 10).Value
Target.Range("A65536").End(3)(2).Resize(UBound(Arr), 10) = Arr
End If
Next
.Close False
End With
End If

End If
End If


res = FindNextFile(hFind, FileData)
Loop Until (res = 0)


finish:
FindClose (hFind)
Loop
End Sub


Function StripNulls(OriginalStr As String) As String
OriginalStr = StrConv(OriginalStr, vbFromUnicode)
If (InStr(OriginalStr, Chr(0)) > 0) Then
OriginalStr = Left(OriginalStr, InStr(OriginalStr, Chr(0)) - 1)
End If
StripNulls = OriginalStr
End Function


Private Sub Test()
Dim DirCount As Integer, fileCount As Integer
Dim Path As String
ActiveSheet.UsedRange.ClearContents
Path = ThisWorkbook.Path
CheckDir Path, DirCount, fileCount
MsgBox "Check Complete - Folder: " & DirCount & " - File: " & fileCount
End Sub


[/GPEcode]
Mạnh chưa Hiểu Hàm sau lắm ... Nếu xài hàm sau thì có thay thế được 3 Hàm trên của Bạn hay không... ý mình muốn đơn gian hóa thêm một tí về API đó mà...

Private Const FILE_ATTRIBUTE_DIRECTORY = &H10
Private Declare Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesW" (ByVal lpFileName As String) As Long
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom