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:
1. Đệ quy đơn giản chỉ là sử dụng hàm đấy trong chính thân hàm đó thôi. ứng dụng thì có thể là duyệt thư mục, tính giai thừa... Đệ quy làm đầy rất nhanh stack, vì vậy dùng nó phải kiểm soát đc độ sâu gọi nó. Trong java android, độ sâu thì khoảng 100 là tạch, PC thì lớn hơn.
2. Về code duyệt thư mục của bạn, nếu bạn thừ duyệt thư mục System32 xem, lâu đấy. Mình thấy nên sử dụng các hàm API trực tiếp của Windows ( các hàm FindFirstFile/FindNextFile/FindClose ) sẽ cho kết quả nhanh hơn.
 
Upvote 0
1. Đệ quy đơn giản chỉ là sử dụng hàm đấy trong chính thân hàm đó thôi. ứng dụng thì có thể là duyệt thư mục, tính giai thừa... Đệ quy làm đầy rất nhanh stack, vì vậy dùng nó phải kiểm soát đc độ sâu gọi nó. Trong java android, độ sâu thì khoảng 100 là tạch, PC thì lớn hơn.
2. Về code duyệt thư mục của bạn, nếu bạn thừ duyệt thư mục System32 xem, lâu đấy. Mình thấy nên sử dụng các hàm API trực tiếp của Windows ( các hàm FindFirstFile/FindNextFile/FindClose ) sẽ cho kết quả nhanh hơn.
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
 
Upvote 0
Gì vậy bồ. Thì tôi để lúc chạy code cho chủ động chọn folder mà...muốn thì set cứng đường dẫn chứ lị

Mã:
Dim dArr(1 To 65000, 1 To 10)
Dim I As Long, X As Long, J As Long


Function Getfile(ByVal Linkfolder As String)
Dim sfi As Object, fi  As Object, oFolder As Object, Wb As Workbook, Sh As Worksheet, Arr
Static fso As Object, pFile As String
pFile = ActiveWorkbook.Name
If fso Is Nothing Then Set fso = CreateObject("Scripting.filesystemobject")
Set oFolder = fso.GetFolder(Linkfolder)
For Each fi In oFolder.Files
If fso.GetExtensionName(fi) Like "*xls*" Then
    If Left(fi.Name, 1) <> "~" Then
    If InStr(1, fi.Name, pFile) <= 0 Then
        Set Wb = Workbooks.Open(fi.Path)
        For Each Sh In Wb.Worksheets
        If Sh.Name = "THU" Then
        Set Sh = Wb.Sheets("THU")
        Arr = Sh.Range("B6", Sh.Range("B65000").End(3)).Resize(, 9).Value
            For X = 1 To UBound(Arr)
                If Len(Arr(X, 1)) Then
                    I = I + 1
                    dArr(I, 1) = I
                    For J = 1 To 9
                        dArr(I, J + 1) = Arr(X, J)
                    Next J
                End If
            Next X
        End If
        Next Sh
        Workbooks(fi.Name).Close
    End If
    End If
End If
Next fi
For Each sfi In oFolder.SubFolders
    Getfile (sfi)
Next
End Function


Sub Muon_XXX()
Application.ScreenUpdating = False
    Dim source As String
'    With Application.FileDialog(msoFileDialogFolderPicker)
'        .Show
'        .AllowMultiSelect = False
'        source = .SelectedItems(1)
'    End With
source = ThisWorkbook.Path
    I = 0
    Getfile (source)
With Sheets("TongHop")
    .Range("A2:J65536").ClearContents
    .Range("A2").Resize(I, 10) = dArr
End With
Application.ScreenUpdating = True
End Sub
Lúc nảy thử vậy OK rồi Bạn Hiền

Mã:
Sub XYZ()
    Dim source As String
    source = ThisWorkbook.Path
    Getfile (source)
    Sheet1.Range("A2:J65536").ClearContents
    Sheet1.Range("A2").Resize(I, 10) = dArr
End Sub
 
Upvote 0
Hình như ít Bạn có hứng với Thuật Toán Đệ Quy thì phải...--=0

Với yêu cầu như bài #14 .... Files và Folder Giả lập như Bài #14 ta sử dụng VBA thì thấy nó đơn giản ...thôi bỏ qua....giờ ta chuyển qua ADO

1/ Sử dụng ADO tổng hợp tất cả các Sheets("THU") trong Folder như đã từng làm bằng VBA trong mấy bài trước.... (Bài này cũng khó hơn VBA một tẹo thôi...)

2/ Sử dụng ADO tổng hợp hết tất cả các Files và tất cả các sheets trong File từ Thư mục cha cho đến thư mục con cháu không xác định tên Sheets ....Gán lên Sheet nếu đúng thì sẻ có 457 dòng....(Bài này thì cũng đau đầu á...+-+-+-+!$@!!--=0)

3/ Lưu ý không sử dụng On Error ... để xử lý lỗi.....(Mạnh thì đang nhức đầu khúc này+-+-+-+!$@!!)

Nếu Bạn nào có nhả hứng thì tham gia code...
xin cảm ơn
 
Upvote 0
Upvote 0
Mấy năm trước mình cũng thử mò cái đệ quy này cơ mà khó nhằn nên "té" +-+-+-++-+-+-+

Bạn có thời gian thì "ngó" 1 chút topic sau, code đã được bạn "Tự động trả lời" sửa lại ngắn gọn súc tích hơn.

Cảm ơn bạn đã có những chia sẻ về món này nhé!

http://www.giaiphapexcel.com/forum/...-paste-hàng-loạt-tên-file&p=710663#post710663
Thì mình cũng đang trên bước đường nghiên cứu thôi ...ngồi không buồn buồn bày trò ra để chơi vậy chứ ...và cũng mong muốn hoc hỏi thêm ở nhiều góc độ khác trong cách xử lý của một vấn đề đó mà....

Triết học 1 tí:

1/ Trong cùng một sự vật hiện tượng ....ta muốn nghiên cứu hay phán xét nó ...

Thì phải xem xét nó trong vận động ở nhiều góc độ khác nhau....thì mới có thể đưa ra được kết luận khá chính xác...

2/ Code két cũng vậy nhiều khi mình viết trên máy mình thấy OK rồi đó ...cứ nghĩ vậy là ngon ...nhưng khi úp bài lên cho người khác sử dụng thì nó mới lòi ra nhiều vấn đề cần xem xét ....và bất chợt nhìn thấy chính khả năng của mình nó bé tẹo như cái kẹo....

Vậy Mạnh lập ra thớt này là vì vậy đó....
 
Lần chỉnh sửa cuối:
Upvote 0
2/ Code két cũng vậy nhiều khi mình viết trên máy mình thấy OK rồi đó ...cứ nghĩ vậy là ngon ...nhưng khi úp bài lên cho người khác sử dụng thì nó mới lòi ra nhiều vấn đề cần xem xét ....và bất chợt nhìn thấy chính khả năng của mình nó bé tẹo như cái kẹo....
Tôi thích câu nói này, thật ra đã xem các bài trong topic này nhưng trình độ của mình về đệ quy thì rất tệ, nên chủ yếu là xem các cao thủ trổ tài thôi. Những bài viết đáng học hỏi, một lần nửa cảm ơn chủ topic.
 
Upvote 0
Mấy năm trước mình cũng thử mò cái đệ quy này cơ mà khó nhằn nên "té" +-+-+-++-+-+-+

Bạn có thời gian thì "ngó" 1 chút topic sau, code đã được bạn "Tự động trả lời" sửa lại ngắn gọn súc tích hơn.

Cảm ơn bạn đã có những chia sẻ về món này nhé!

http://www.giaiphapexcel.com/forum/...-paste-hàng-loạt-tên-file&p=710663#post710663

mình để ý thấy hình như bạn "tự động trả lời" là fan hâm mộ của anh hpkhuong thì phải
bằng chứng là bạn "tự động trả lời" học tập sử dụng từ khóa static của anh hpkhuong ở bài #17
và đây cũng là câu trả lời cho nghi ngại của bạn Hau151978

Hình như code này khởi tạo rất nhiều object. Để an toàn, ta nên set =nothing ở cuối thủ tục.
 
Upvote 0
Bằng chứng là anh hpkhuong học được từ anh "tự động trả lời" cái vụ rút gọn đó đó...haha....--=0--=0--=0
---------------------
Vì lang thang hôm bữa bữa...gặp bài của anh í rút gọn rất chi là hay nên ứng dụng đó mà lị...@$@!^%
Mạnh chưa hiểu sâu cái static lắm ....hai bạn dro và hpk chỉ cho cái đi ....%#^#$
 
Upvote 0
Mình không biết diễn giải về đệ quy, mặc dù cũng cố lắm lắm nhưng cũng chỉ viết ra code này. Cũng tạm gọi là đệ quy chút chút. Theo mình hiểu, đệ quy là dùng 1 thủ tục hoặc 1 hàm nào đó và gọi lại chính nó. Nói chung là phức tạp bỏ xừ.

PHP:
Sub ArraySort()
'Written by QuangHai
Dim Data(), Temp As String
Dim FirsrtRow As Long, FirstCol As String, SortOrder()
Dim TotalCols As Byte, Row As Long, J As Long
SortOrder = Array(2, 3)
With Sheets("Nguon")
   Data = .Range("A3", .[M65536].End(3)).Value
End With
TotalCols = UBound(Data, 2)
ReDim Preserve Data(1 To UBound(Data), 1 To (TotalCols + 1))
For Row = 1 To UBound(Data, 1)
   For J = 0 To UBound(SortOrder)
      If IsDate(Data(Row, SortOrder(J))) Then
         Temp = Temp & CLng(Data(Row, SortOrder(J)))
      Else
         Temp = Temp & Space(2) & Format(Data(Row, SortOrder(J)), String(15, "0"))
      End If
   Next
   Data(Row, TotalCols + 1) = Temp
   Temp = Empty
Next
QuickSort Data, LBound(Data), UBound(Data)
Sheets("Dich").[A3].Resize(UBound(Data), TotalCols) = Data
End Sub
'**************************
Sub QuickSort(Arr(), Min As Long, Max As Long)
  Dim MidVal As Variant, TempVal As Variant
  Dim TempMin&, TempMax&, LastCol&, TotalCol&
  TempMin = Min
  TempMax = Max
  LastCol = UBound(Arr, 2)
  MidVal = Arr((Min + Max) \ 2, LastCol)
  Do While TempMin <= TempMax
    Do While Arr(TempMin, LastCol) < MidVal And TempMin < Max
      TempMin = TempMin + 1
    Loop
    Do While MidVal < Arr(TempMax, LastCol) And TempMax > Min
      TempMax = TempMax - 1
    Loop
    If TempMin <= TempMax Then
      For TotalCol = 1 To LastCol
         TempVal = Arr(TempMin, TotalCol)
         Arr(TempMin, TotalCol) = Arr(TempMax, TotalCol)
         Arr(TempMax, TotalCol) = TempVal
      Next
      TempMin = TempMin + 1
      TempMax = TempMax - 1
    End If
  Loop
  If Min < TempMax Then QuickSort Arr, Min, TempMax
  If TempMin < Max Then QuickSort Arr, TempMin, Max
End Sub
 
Upvote 0
Mình không biết diễn giải về đệ quy, mặc dù cũng cố lắm lắm nhưng cũng chỉ viết ra code này. Cũng tạm gọi là đệ quy chút chút. Theo mình hiểu, đệ quy là dùng 1 thủ tục hoặc 1 hàm nào đó và gọi lại chính nó. Nói chung là phức tạp bỏ xừ.

PHP:
Sub ArraySort()
'Written by QuangHai
Dim Data(), Temp As String
Dim FirsrtRow As Long, FirstCol As String, SortOrder()
Dim TotalCols As Byte, Row As Long, J As Long
SortOrder = Array(2, 3)
With Sheets("Nguon")
   Data = .Range("A3", .[M65536].End(3)).Value
End With
TotalCols = UBound(Data, 2)
ReDim Preserve Data(1 To UBound(Data), 1 To (TotalCols + 1))
For Row = 1 To UBound(Data, 1)
   For J = 0 To UBound(SortOrder)
      If IsDate(Data(Row, SortOrder(J))) Then
         Temp = Temp & CLng(Data(Row, SortOrder(J)))
      Else
         Temp = Temp & Space(2) & Format(Data(Row, SortOrder(J)), String(15, "0"))
      End If
   Next
   Data(Row, TotalCols + 1) = Temp
   Temp = Empty
Next
QuickSort Data, LBound(Data), UBound(Data)
Sheets("Dich").[A3].Resize(UBound(Data), TotalCols) = Data
End Sub
'**************************
Sub QuickSort(Arr(), Min As Long, Max As Long)
  Dim MidVal As Variant, TempVal As Variant
  Dim TempMin&, TempMax&, LastCol&, TotalCol&
  TempMin = Min
  TempMax = Max
  LastCol = UBound(Arr, 2)
  MidVal = Arr((Min + Max) \ 2, LastCol)
  Do While TempMin <= TempMax
    Do While Arr(TempMin, LastCol) < MidVal And TempMin < Max
      TempMin = TempMin + 1
    Loop
    Do While MidVal < Arr(TempMax, LastCol) And TempMax > Min
      TempMax = TempMax - 1
    Loop
    If TempMin <= TempMax Then
      For TotalCol = 1 To LastCol
         TempVal = Arr(TempMin, TotalCol)
         Arr(TempMin, TotalCol) = Arr(TempMax, TotalCol)
         Arr(TempMax, TotalCol) = TempVal
      Next
      TempMin = TempMin + 1
      TempMax = TempMax - 1
    End If
  Loop
  If Min < TempMax Then QuickSort Arr, Min, TempMax
  If TempMin < Max Then QuickSort Arr, TempMin, Max
End Sub
dữ liệu Sheet nguon là sao Anh để Sort nó ra kết quả
 
Upvote 0
Lâu lắm không tham gia bài nào, nay xin phép võ vẽ vài câu cùng mọi người nhé...
Giải thích về Đệ quy...
Lấy một ví dụ đơn giản thế này nhé:
3 đại gia đình có 5 thế hệ xếp hàng ngang thành 5 hàng sao cho:
Hàng 1 là tất cả những người thuộc thế hệ 1;
Hàng 2 là tất cả những người thuộc thế hệ 2
...
Hàng 5 là tất cả những người thuộc thế hệ 5.


Chọn một người (anh A) đứng vị trí 1 của hàng thứ 5, hãy xác định người đàn ông nào thuộc hàng 1 là cùng đại gia đình với người ở hàng thứ 5.
Các bạn sẽ giải bài toán này bằng cách nào? Dùng biện pháp mô tả, không lập trình nhé.


Khi giải được bài toán này là các bạn hiểu được đệ quy là gì?
Trong thực tế thì Đệ quy là việc một chương trình gọi lại chính nó trong quá trình thực hiện (đệ quy đơn). Và có thể có phép đệ quy sử dụng nhiều chương trình con khác và chúng có thể gọi lẫn nhau (đệ quy tương hỗ) nhưng cách thực hiện là như nhau tùy theo tính phức tạp của bài toán.


Bản chất của Đệ quy là giải pháp đơn giản hóa mối quan hệ nhiều tầng bằng cách xử lý từng cặp quan hệ có mối quan hệ gần nhau nhất, khi thỏa mãn điều kiện nào đó thì mới kết thúc còn chưa thỏa mãn thì tiếp tục xử lý cặp quan hệ ở mức độ tiếp theo.


Ứng dụng Đệ quy là rất rộng lớn và tùy từng ngôn ngữ lập trình mà nó có giới hạn khác nhau.
Quay lại bài toán trên, cách làm như sau:
1. Hỏi ngưởi đứng đầu hàng 5 xem có quan hệ với anh bạn A không?
+ Nếu CÓ - Dừng, đổi anh A thành anh bạn mới này và quay lại 1 với người đầu ở hàng 4;
+ nếu KHÔNG, hỏi tiếp người thứ 2 cho đến khi gặp câu trả lời là có
Sau nhiều vòng ta sẽ đến được người đứng hàng 1 - và nếu là CÓ thì kết thúc toàn bộ quá trình tìm kiếm


Trong khoa học máy tính, mỗi lần chương trình gọi chính nó, một khu vực bộ nhớ mới sẽ được dành ra để chứa chương trình cho đến khi ra kết quả.
Cái này người ta gọi đó là Stack và nếu không đến được kết quả cuối cùng, ta sẽ gây tràn bộ nhớ và làm cho toàn bộ hệ thống dừng hoạt động. Để tránh điều này, người ta đặt ra các giới hạn của số lượng Stack để tránh đổ vỡ cho hệ thống, khi đạt số lượng đó mà chương trình không ra kết quả thì trình quản lý ngôn ngữ lập trình sẽ dừng lại và báo lỗi.


Vậy khi nào dùng đệ quy:
+ Khi bạn không dự đoán được độ sâu tìm kiếm (số hàng phả hệ trong bài toán trên)
+ Khi các mối quan hệ là tương đối đơn giản và bạn có thể đánh giá được hết các tình huống quan hệ


Cấu trúc đệ quy bao gồm
Phần khởi sự: Xử lý tham số đầu vào đơn giản nhất để dừng chương trình
Phần đệ quy: Truyền tham số mới (tráo đổi vị trí) cho chính chương trình để nó tiếp tục xử lý


Vậy với bài toán tìm tất cả các file Excel trong một thư mục sẽ được giải quyết thế này:


[GPECODE=vb]A::Thủ tục gọi đệ quy: Truyền các tham số đầu vào như [Đường dẫn cần tìm]
<Bắt đầu thủ tục A>
[Danh sách File Excel] = B[Đường dẫn ban đầu]
<Bắt đầu thủ tục A>


B::Thủ tục đệ quy [Đường dẫn]
<Bắt đầu hàm B>
Biến C - Tên File
+ Vòng lặp Kiểm tra tất cả các đối tượng trong thư mục
{
+ Nếu đối tượng hiện tại là
{
+ Thư mục: Gọi B [Đướng dẫn của thư mục này]
+ File:
+ Nếu là File Excel: Thêm tên File vào biến C
+ Còn ... Bỏ qua
}
}
+ Kết thúc vòng lặp trả về giá trị của Hàm B là giá trị C.
<Kết thúc Hàm B::>[/GPECODE]


Vậy đấy Đệ quy là như thế...
Quay lại bài toán tìm File... các bạn có thể sử dụng chung 1 biến Fso Hệ thống được khởi tạo từ thủ tục A
Bài toán sau đây của tôi là liệt kê tất cả các File Excel trong 1 thư mục cho trước


[GPECODE=vb]Sub ListFiles()
Dim fs As Object, FileStr As String, FileArr as Variant

'Creating File System Object
Set fs = CreateObject("Scripting.FileSystemObject")

'Gọi thủ tục liệt kê các File trong 1 thư mục kể cả thư mục con
FileStr = GetFiles(fs, "C:\Windows", "|", "xls")
Set fs = Nothing
If Len(FileStr) > 1 Then
FileStr = Mid(FileStr, Len(initSp) + 1)
' Loại bỏ những danh sách có 2 dấu ||
FileStr = Replace(FileStr, "||", "|")
End If
' Kết quả là danh sách File dưới dạng chuỗi và ta chuyển thành mảng để xử lý sau
FileArr = Split(FileStr,"|")

' Các việc khác cần làm...
' In danh sách ra Sheet1
Dim rng As Range
Set rng = Sheet1.Cells(1)
Set rng = rng.Resize(UBound(FileArr), 1)
rng.Value = Application.Transpose(FileArr)
End Function


Private Function GetFiles(Fso As Object, FolderName As String, sp As String, flExt As String) As String
On Error Resume Next
Dim ObjFolder As Object
Dim ObjSubFolders As Object
Dim ObjSubFolder As Object
Dim ObjFiles As Object
Dim ObjFile As Object
Dim OutString As String

Set ObjFolder = Fso.GetFolder(FolderName)
Set ObjFiles = ObjFolder.files

'Ghi tất cả các File thỏa mãn vào biến nhớ OutString
For Each ObjFile In ObjFiles
If ObjFile.name <> "" Then
If LCase(GetFileExtension(ObjFile.name)) Like LCase(flExt) Then
OutString = OutString & sp & ObjFile.path
End If
End If
Next
'Liệt kê tất cả các thư mục con
Set ObjSubFolders = ObjFolder.SubFolders

For Each ObjFolder In ObjSubFolders
'Lấy tất cả các File trong thư mục con
OutString = OutString & sp & GetFiles(Fso, ObjFolder.path, sp, flExt)
Next
' Trả về kết quả
GetFiles = OutString
End Function


Function GetFileExtension(FileName As String) As String
' Trả về phần đuôi của file
On Error Resume Next
GetFileExtension = Mid(FileName, InStrRev(FileName, ".") + 1)
End Function[/GPECODE]


LƯU Ý: Tuy nhiên, thường thì nên tránh lạm dụng đệ quy vì nó sẽ gây lỗi nếu ta không dự tính được hết các tình huống phát sinh. Cái gì có thể giải quyết theo cách thường thì cứ thế mà làm.
Tôi không hay dùng đệ quy trong các bài toán của mình song có những lúc cũng cần. Ví dụ:
+ Liệt kê các File trong thư mục
+ Duyệt qua các đối tượng trong 1 TreeView (Cây)
+ Xử lý công thức như trong Excel ...


Và... Trong thiết kế đệ quy::
+ Phải nắm được mối quan hệ giữa các đối tượng xử lý;
+ Giải quyết được tất cả các tình huống phát sinh khi đánh giá một cặp quan hệ
 
Lần chỉnh sửa cuối:
Upvote 0
Lâu lắm không tham gia bài nào, nay xin phép võ vẽ vài câu cùng mọi người nhé...
Giải thích về Đệ quy...
Lấy một ví dụ đơn giản thế này nhé:
3 đại gia đình có 5 thế hệ xếp hàng ngang thành 5 hàng sao cho:
Hàng 1 là tất cả những người thuộc thế hệ 1;
Hàng 2 là tất cả những người thuộc thế hệ 2
...
Hàng 5 là tất cả những người thuộc thế hệ 5.


Chọn một người (anh A) đứng vị trí 1 của hàng thứ 5, hãy xác định người đàn ông nào thuộc hàng 1 là cùng đại gia đình với người ở hàng thứ 5.
Các bạn sẽ giải bài toán này bằng cách nào? Dùng biện pháp mô tả, không lập trình nhé.


Khi giải được bài toán này là các bạn hiểu được đệ quy là gì?
Trong thực tế thì Đệ quy là việc một chương trình gọi lại chính nó trong quá trình thực hiện (đệ quy đơn). Và có thể có phép đệ quy sử dụng nhiều chương trình con khác và chúng có thể gọi lẫn nhau (đệ quy tương hỗ) nhưng cách thực hiện là như nhau tùy theo tính phức tạp của bài toán.


Bản chất của Đệ quy là giải pháp đơn giản hóa mối quan hệ nhiều tầng bằng cách xử lý từng cặp quan hệ có mối quan hệ gần nhau nhất, khi thỏa mãn điều kiện nào đó thì mới kết thúc còn chưa thỏa mãn thì tiếp tục xử lý cặp quan hệ ở mức độ tiếp theo.


Ứng dụng Đệ quy là rất rộng lớn và tùy từng ngôn ngữ lập trình mà nó có giới hạn khác nhau.
Quay lại bài toán trên, cách làm như sau:
1. Hỏi ngưởi đứng đầu hàng 5 xem có quan hệ với anh bạn A không?
+ Nếu CÓ - Dừng, đổi anh A thành anh bạn mới này và quay lại 1 với người đầu ở hàng 4;
+ nếu KHÔNG, hỏi tiếp người thứ 2 cho đến khi gặp câu trả lời là có
Sau nhiều vòng ta sẽ đến được người đứng hàng 1 - và nếu là CÓ thì kết thúc toàn bộ quá trình tìm kiếm


Trong khoa học máy tính, mỗi lần chương trình gọi chính nó, một khu vực bộ nhớ mới sẽ được dành ra để chứa chương trình cho đến khi ra kết quả.
Cái này người ta gọi đó là Stack và nếu không đến được kết quả cuối cùng, ta sẽ gây tràn bộ nhớ và làm cho toàn bộ hệ thống dừng hoạt động. Để tránh điều này, người ta đặt ra các giới hạn của số lượng Stack để tránh đổ vỡ cho hệ thống, khi đạt số lượng đó mà chương trình không ra kết quả thì trình quản lý ngôn ngữ lập trình sẽ dừng lại và báo lỗi.


Vậy khi nào dùng đệ quy:
+ Khi bạn không dự đoán được độ sâu tìm kiếm (số hàng phả hệ trong bài toán trên)
+ Khi các mối quan hệ là tương đối đơn giản và bạn có thể đánh giá được hết các tình huống quan hệ


Cấu trúc đệ quy bao gồm
Phần khởi sự: Xử lý tham số đầu vào đơn giản nhất để dừng chương trình
Phần đệ quy: Truyền tham số mới (tráo đổi vị trí) cho chính chương trình để nó tiếp tục xử lý


Vậy với bài toán tìm tất cả các file Excel trong một thư mục sẽ được giải quyết thế này:


Mã:
A::Thủ tục gọi đệ quy: Truyền các tham số đầu vào như [Đường dẫn cần tìm]
<Bắt đầu thủ tục A>
    [Danh sách File Excel] = B[Đường dẫn ban đầu]
<Bắt đầu thủ tục A>


B::Thủ tục đệ quy [Đường dẫn]
<Bắt đầu hàm B>
Biến C - Tên File
+ Vòng lặp Kiểm tra tất cả các đối tượng trong thư mục
{
    + Nếu đối tượng hiện tại là 
    {
        + Thư mục: Gọi B [Đướng dẫn của thư mục này]
        + File:
            + Nếu là File Excel: Thêm tên File vào biến C
            + Còn ... Bỏ qua
    }
}
+ Kết thúc vòng lặp trả về giá trị của Hàm B là giá trị C.
<Kết thúc Hàm B::>
Vậy đấy Đệ quy là như thế...
Quay lại bài toán tìm File... các bạn có thể sử dụng chung 1 biến Fso Hệ thống được khởi tạo từ thủ tục A
Bài toán sau đây của tôi là liệt kê tất cả các File Excel trong 1 thư mục cho trước


Mã:
Sub ListFiles()
    Dim fs As Object, FileStr As String, FileArr as Variant
     
    'Creating File System Object
    Set fs = CreateObject("Scripting.FileSystemObject")
     
    'Gọi thủ tục liệt kê các File trong 1 thư mục kể cả thư mục con
    FileStr = GetFiles(fs, "C:\Windows", "|", "xls")
    Set fs = Nothing
    If Len(FileStr) > 1 Then
        FileStr = Mid(FileStr, Len(initSp) + 1)
        ' Loại bỏ những danh sách có 2 dấu ||
        FileStr = Replace(FileStr, "||", "|")
    End If
    ' Kết quả là danh sách File dưới dạng chuỗi và ta chuyển thành mảng để xử lý sau
    FileArr = Split(FileStr,"|")
    ' Các việc khác cần làm...
End Function


Private Function GetFiles(Fso As Object, FolderName As String, sp As String, flExt As String) As String
    On Error Resume Next
    Dim ObjFolder As Object
    Dim ObjSubFolders As Object
    Dim ObjSubFolder As Object
    Dim ObjFiles As Object
    Dim ObjFile As Object
    Dim OutString As String
    
    Set ObjFolder = Fso.GetFolder(FolderName)
    Set ObjFiles = ObjFolder.files
     
    'Ghi tất cả các File thỏa mãn vào biến nhớ OutString
    For Each ObjFile In ObjFiles
        If ObjFile.name <> "" Then
            If LCase(GetFileExtension(ObjFile.name)) Like LCase(flExt) Then
                OutString = OutString & sp & ObjFile.path
            End If
        End If
    Next
    'Liệt kê tất cả các thư mục con
    Set ObjSubFolders = ObjFolder.SubFolders
     
    For Each ObjFolder In ObjSubFolders
        'Lấy tất cả các File trong thư mục con
        OutString = OutString & sp & GetFiles(Fso, ObjFolder.path, sp, flExt)
    Next
    ' Trả về kết quả
    GetFiles = OutString
End Function


Function GetFileExtension(FileName As String) As String
    ' Trả về phần đuôi của file
    On Error Resume Next
    GetFileExtension = Mid(FileName, InStrRev(FileName, ".") + 1)
End Function


LƯU Ý: Tuy nhiên, thường thì nên tránh lạm dụng đệ quy vì nó sẽ gây lỗi nếu ta không dự tính được hết các tình huống phát sinh. Cái gì có thể giải quyết theo cách thường thì cứ thế mà làm.
Tôi không hay dùng đệ quy trong các bài toán của mình song có những lúc cũng cần. Ví dụ:
+ Liệt kê các File trong thư mục
+ Duyệt qua các đối tượng trong 1 TreeView (Cây)
+ Xử lý công thức như trong Excel ...


Và... Trong thiết kế đệ quy::
+ Phải nắm được mối quan hệ giữa các đối tượng xử lý;
+ Giải quyết được tất cả các tình huống phát sinh khi đánh giá một cặp quan hệ
Mình đọc tới lui cũng chưa hiểu chạy Sub ListFiles sẽ lấy kết quả ra hình thù gì ...??hay gán lên Sheet như thế nào Bạn ... có thể chỉ thêm cho mình được không
xin cảm ơn
 
Upvote 0
Bạn xem đoạn này
[GPECODE=vb]' Các việc khác cần làm...
' In danh sách ra Sheet1
Dim rng As Range
Set rng = Sheet1.Cells(1)
Set rng = rng.Resize(UBound(FileArr), 1)
rng.Value = Application.Transpose(FileArr)[/GPECODE]
Nó in ra sheet1 danh sách file... Tôi làm ví dụ để các bạn hiểu về Đệ quy thôi
(nhớ thay đổi tham số đường dẫn ban đầu nhé)
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn xem đoạn này
[GPECODE=vb]' Các việc khác cần làm...
' In danh sách ra Sheet1
Dim rng As Range
Set rng = Sheet1.Cells(1)
Set rng = rng.Resize(UBound(FileArr), 1)
rng.Value = Application.Transpose(FileArr)[/GPECODE]
Nó in ra sheet1 danh sách file... Tôi làm ví dụ để các bạn hiểu về Đệ quy thôi
(nhớ thay đổi tham số đường dẫn ban đầu nhé)
Vậy code ở bài #1 Mình viết như vậy có phải là đệ quy không Bạn ...?!

Mình không Rành lắm thấy ai đó viết bắt trước viết vậy thôi chứ....còn hiểu thì hông biết
 
Lần chỉnh sửa cuối:
Upvote 0
Đó chính là đệ quy - "Một hàm/ Thủ tục gọi lại chính nó" trong tiến trình thực hiện.
Không nên quá lo sợ về đệ quy nhé! Nó đơn giản thôi, không quá phức tạp nếu bạn hiểu rõ các mối quan hệ trong bài toán lớn.
(Hãy đọc cách phân tích bài toán phả hệ mà tôi viết, nếu không thì có thể nghiên cứu về thuật giải Giai thừa nữa...)
Thân
 
Upvote 0
Đó chính là đệ quy - "Một hàm/ Thủ tục gọi lại chính nó" trong tiến trình thực hiện.
Không nên quá lo sợ về đệ quy nhé! Nó đơn giản thôi, không quá phức tạp nếu bạn hiểu rõ các mối quan hệ trong bài toán lớn.
(Hãy đọc cách phân tích bài toán phả hệ mà tôi viết, nếu không thì có thể nghiên cứu về thuật giải Giai thừa nữa...)
Thân
Thế mà có ai đó keo nếu đã sử dụng đệ quy thì sẽ không có vòng lặp làm gì và đó không phải là đệ quy đúng nghĩa ...Mình cứ nghĩ Mình theo cái môn phái tà đạo nào chăng...

Và cách sử dụng
If InSub Then Bạn thấy thế nào ....

Xin cảm ơn
 
Upvote 0
Thế mà có ai đó keo nếu đã sử dụng đệ quy thì sẽ không có vòng lặp làm gì và đó không phải là đệ quy đúng nghĩa ...Mình cứ nghĩ Mình theo cái môn phái tà đạo nào chăng...

Và cách sử dụng
If InSub Then Bạn thấy thế nào ....

Xin cảm ơn
Mã:
Function Giaithua(n As Long) As Long
  If (n = 1) Then
    Giaithua = 1
    Exit Function
  End If
  Giaithua = n * Giaithua(n - 1)
End Function
bản chất của đệ quy là thay thế vòng lập đó anh.
 
Upvote 0
Web KT

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

Back
Top Bottom