Bàn về thuật toán sort mảng (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Hoàng Trọng Nghĩa

Chuyên gia GPE
Thành viên BQT
Moderator
Tham gia
17/8/08
Bài viết
8,662
Được thích
16,725
Giới tính
Nam
Hổm rày chưa thấy đề tài nào sôi nổi, giờ thử đố một đề tài xem có tạo hứng thú cho mọi người không.

Nếu tôi có một chuỗi với các số (dương) lộn xộn:

Chuỗi = "1, 8, 6, 4, 5, 11, 12, 13, 16, 15, 20, 14, 10, 7"

Giờ, tôi sẽ viết hàm như thế nào để dãy số trên được lược lại, và có kết quả như dưới?

Kết quả = "1, 4-8, 10-16, 20"

Các bạn thử xem nào!
 
Lần chỉnh sửa cuối:
Hổm rày chưa thấy đề tài nào sôi nổi, giờ thử đố một đề tài xem có tạo hứng thú cho mọi người không.

Nếu tôi có một chuỗi với các số lộn xộn:

Chuỗi = "1, 8, 6, 4, 5, 11, 12, 13, 16, 15, 20, 14, 10, 7"

Giờ, tôi sẽ viết hàm như thế nào để dãy số trên được lược lại, và có kết quả như dưới?

Kết quả = "1, 4-8, 10-16, 20"

Các bạn thử xem nào!

Bài này nhớ có người hỏi rồi và cũng đã từng làm rồi thì phải
 
Upvote 0
Bài này nhớ có người hỏi rồi và cũng đã từng làm rồi thì phải

Cái này em chỉ mới làm chiều nay thôi, còn ai đã từng hỏi thì em chưa biết. Vậy sẳn bài này, Thầy đưa cái bài Thầy đã làm để tham khảo luôn đi Thầy nhé!
 
Upvote 0
Hổm rày chưa thấy đề tài nào sôi nổi, giờ thử đố một đề tài xem có tạo hứng thú cho mọi người không.

Nếu tôi có một chuỗi với các số lộn xộn:

Chuỗi = "1, 8, 6, 4, 5, 11, 12, 13, 16, 15, 20, 14, 10, 7"

Giờ, tôi sẽ viết hàm như thế nào để dãy số trên được lược lại, và có kết quả như dưới?

Kết quả = "1, 4-8, 10-16, 20"

Các bạn thử xem nào!
Làm đại 2 cách cách nào được thì lấy :D.
Phương án 1
PHP:
Function Function1(Str As String) As String
Dim Arr, i As Long, j As Long, Tmp, Count As Long
Arr = Split(Str, ", ")
For i = LBound(Arr) To UBound(Arr)
    For j = i + 1 To UBound(Arr)
        If CLng(Arr(j)) < CLng(Arr(i)) Then
            Tmp = Arr(j):   Arr(j) = Arr(i):    Arr(i) = Tmp
        End If
    Next
Next
Tmp = Arr(LBound(Arr)):    Count = 1:   Str = ""
For i = LBound(Arr) + 1 To UBound(Arr)
    If CLng(Arr(i)) = Tmp + Count Then
        Count = Count + 1
    Else
        Str = Str & ", " & Tmp & IIf(Count > 1, "-" & (Tmp + Count - 1), "")
        Tmp = CLng(Arr(i))
        Count = 1
    End If
Next
Str = Str & ", " & Tmp & IIf(Count > 1, "-" & (Tmp + Count - 1), "")
Function1 = Replace(Str, ", ", "", 1, 1)
End Function
Phương án 2
PHP:
Function Function2(Str As String) As String
Dim Arr, i As Long, j As Long, Tmp, Check As Boolean
On Error Resume Next
Arr = Split(Str, ", ")
For i = LBound(Arr) To UBound(Arr)
    For j = i + 1 To UBound(Arr)
        If CLng(Arr(j)) < CLng(Arr(i)) Then
            Tmp = Arr(j):   Arr(j) = Arr(i):    Arr(i) = Tmp
        End If
    Next
    If CLng(Arr(i)) = Arr(i - 1) + 1 Then
        If Check Then
            Arr(i - 1) = ""
        Else
            Arr(i - 1) = Arr(i - 1) & "-"
            Check = True
        End If
    Else
        Arr(i - 1) = Arr(i - 1) & ", "
        Check = False
    End If
Next
Function2 = Join(Arr, "")
End Function
 
Upvote 0
Hổm rày chưa thấy đề tài nào sôi nổi, giờ thử đố một đề tài xem có tạo hứng thú cho mọi người không.

Nếu tôi có một chuỗi với các số lộn xộn:

Chuỗi = "1, 8, 6, 4, 5, 11, 12, 13, 16, 15, 20, 14, 10, 7"

Giờ, tôi sẽ viết hàm như thế nào để dãy số trên được lược lại, và có kết quả như dưới?

Kết quả = "1, 4-8, 10-16, 20"

Các bạn thử xem nào!
*Anh ra đề bài như vậy --> chắc là để so sánh giải thuật
*Bài này mà anh đố theo kiểu : không dùng mảng, không dùng vòng lặp , chắc là em potay.com-0-/.
Em dùng hàm tự tạo sau :
[GPECODE=vb]
Function Umsbala(str$) As String
Dim tmpArr, Arr(0 To 100)
Dim i&, j&, tmp$
tmpArr = Split(str, ",")
For i = 0 To UBound(tmpArr)
j = tmpArr(i)
Arr(j) = j
Next
For i = 0 To 100
If Len(Arr(i)) Then
For j = i + 1 To 100
If Len(Arr(j)) Then
If Len(Arr(j + 1)) Then
Arr(j) = ""
Else
Arr(j) = "-" & Arr(j) & ","
i = j
Exit For
End If
Else
Arr(i) = Arr(i) & ","
Exit For
End If
Next
End If
Next
tmp = Join(Arr, "")
Umsbala = Left(tmp, Len(tmp) - 1)
End Function
[/GPECODE]
[GPECODE=vb]
Sub Ktr()
MsgBox Umsbala("1, 8, 6, 4, 5, 11, 12, 13, 16, 15, 20, 14, 10, 7")
End Sub
[/GPECODE]
 
Upvote 0
*Anh ra đề bài như vậy --> chắc là để so sánh giải thuật
*Bài này mà anh đố theo kiểu : không dùng mảng, không dùng vòng lặp , chắc là em potay.com-0-/.
Em dùng hàm tự tạo sau :
Mã:
Function Umsbala(str$) As String
    .....
        [B]For i = 0 To [COLOR=#ff0000]100[/COLOR][/B]

Tôi không hiểu tại sao lại có cái vụ For i = 0 to 100 ở đây nhỉ?
Ý tôi muốn nói đến con số 100 ấy ---> Tại sao là 100 mà không là số nào khác?
 
Upvote 0
Tôi không hiểu tại sao lại có cái vụ For i = 0 to 100 ở đây nhỉ?
Ý tôi muốn nói đến con số 100 ấy ---> Tại sao là 100 mà không là số nào khác?

dạ, số "đo đỏ" >= Max(Slpit(Str,",")) --> ý tưởng của em là sắp xếp mảng tăng dần ,dựa vào chỉ số của một mảng phụ , cụ thể:
*ta có mảng 1,2,10,16,20,4
* xây dựng một mảng phu: Arr(1) = 1, Arr(2) = 2,Arr(3) ="",...Arr(10) =10
* Cách sắp xếp này của em tiết kiệm "được" 1 vòng for..next, nhưng mà "mất" cái gì em cũng không biết @#!^%
* Như vậy con số "đỏ đỏ"em chọn = 100 vì ví dụ anh nghĩa đưa ra có giả trị các con số < 100,-0-/.

p/s : em xem lại thấy code em viết quả là "chuối củ "
 
Lần chỉnh sửa cuối:
Upvote 0
Làm quá trời làm sao mà nhớ, nhưng tôi chắc rằng đã từng làm bài gần giống vậy
Nói chung giải thuật bài này cũng chẳng có gì để gọi là ĐỐ VUI cả

Bài này có 2 việc cần bàn đến, nếu dãy số không có số trùng nhau, thì có thể huuthang_bd đã làm hoàn toàn đúng.

Trường hợp trong dãy số có một hoặc nhiều số trùng nhau, thì giải thuật sẽ được đưa ra 2 hướng:

Chuỗi = "1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15,14,10,7,20"

1) Lược số không giữ số trùng (lược duy nhất)

Kết quả = "1-5, 7-16, 20"

2) Lược số, nhưng vẫn để tồn tại số trùng.

Kết quả = "1, 1, 1-5, 7-9, 9-11, 11, 11-15, 15-16, 16, 20, 20"

Như thế cũng thú vị phải vậy không ạ?
 
Lần chỉnh sửa cuối:
Upvote 0
*Anh ra đề bài như vậy --> chắc là để so sánh giải thuật
*Bài này mà anh đố theo kiểu : không dùng mảng, không dùng vòng lặp , chắc là em potay.com-0-/.
Em dùng hàm tự tạo sau :
[GPECODE=vb]
Function Umsbala(str$) As String
Dim tmpArr, Arr(0 To 100)
Dim i&, j&, tmp$
tmpArr = Split(str, ",")
For i = 0 To UBound(tmpArr)
j = tmpArr(i)
Arr(j) = j
Next
For i = 0 To 100
If Len(Arr(i)) Then
For j = i + 1 To 100
If Len(Arr(j)) Then
If Len(Arr(j + 1)) Then
Arr(j) = ""
Else
Arr(j) = "-" & Arr(j) & ","
i = j
Exit For
End If
Else
Arr(i) = Arr(i) & ","
Exit For
End If
Next
End If
Next
tmp = Join(Arr, "")
Umsbala = Left(tmp, Len(tmp) - 1)
End Function
[/GPECODE]
[GPECODE=vb]
Sub Ktr()
MsgBox Umsbala("1, 8, 6, 4, 5, 11, 12, 13, 16, 15, 20, 14, 10, 7")
End Sub
[/GPECODE]

Ý tưởng của bạn cũng rất hay đấy, nếu sửa lại một chút là được, dùng cho trường hợp lược duy nhất:

Mã:
Function Umsbala(str$) As String
    Dim tmpArr, [COLOR=#ff0000]Arr()[/COLOR], [COLOR=#0000cd]iMax As Long[/COLOR]
    Dim i&, j&
        tmpArr = Split(str, ",")
        For i = 0 To UBound(tmpArr)
            j = tmpArr(i)
[COLOR=#0000cd]            If j > iMax Then iMax = j[/COLOR]
[COLOR=#ff0000]            ReDim Preserve Arr(0 To iMax)[/COLOR]
            Arr(j) = j
        Next
        For i = 0 To [COLOR=#0000cd]iMax[/COLOR]
            If Len(Arr(i)) Then
                For j = i + 1 To [COLOR=#0000cd]iMax[/COLOR]
                    If Len(Arr(j)) Then
                        If Len(Arr(j + 1)) Then
                            Arr(j) = ""
                        Else
                            Arr(j) = "-" & Arr(j) & ","
                            i = j
                            Exit For
                        End If
                    Else
                        Arr(i) = Arr(i) & ","
                        Exit For
                    End If
                Next
            End If
        Next
[COLOR=#0000cd]        Umsbala = Join(Arr, "")[/COLOR]
End Function
 
Upvote 0
^^ thì là a Nghĩa đưa ra 1 ví dụ, nên em cũng ví dụ con số "100" luôn, --> còn nếu tổng quát thì phải tìm max của chuỗi đưa vào!:-=

Đúng là như thế, nhưng nếu bạn làm như thế thì Thầy NDU chả phải góp ý cho bạn đâu hen. Cái hay của topic này là như vậy, đố để giải, giải để học, học qua học lại từ đó tất cả đều được học và đều tiến bộ là như thế đó.
 
Upvote 0
Bài này có 2 việc cần bàn đến, nếu dãy số không có số trùng nhau, thì có thể huuthang_bd đã làm hoàn toàn đúng.

Trường hợp trong dãy số có một hoặc nhiều số trùng nhau, thì giải thuật sẽ được đưa ra 2 hướng:

Chuỗi = "1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15,14,10,7,20"

1) Lược số không giữ số trùng (lược duy nhất)

Kết quả = "1-5, 7-16, 20"

2) Lược số, nhưng vẫn để tồn tại số trùng.

Kết quả = "1, 1, 1-5, 7-9, 9-11, 11, 11-15, 15-16, 16, 20, 20"

Như thế cũng thú vị phải vậy không ạ?

Nếu có số trùng thì cả 2 code của tôi đang thực hiện theo hướng thứ 2. Còn nếu loại bỏ số trùng thì cũng đơn giản. Trong quá trình sắp xếp lại mảng, cái nào trùng thì bỏ ra. Ta sẽ được mảng duy nhất.
 
Upvote 0
Nếu có số trùng thì cả 2 code của tôi đang thực hiện theo hướng thứ 2. Còn nếu loại bỏ số trùng thì cũng đơn giản. Trong quá trình sắp xếp lại mảng, cái nào trùng thì bỏ ra. Ta sẽ được mảng duy nhất.

Chuỗi = "1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15 ,14,10,7,20"

Với chuỗi số đó, hướng 2 (hàm Function2) thì cho kết quả:

Kết quả = "1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15 ,14,10,7,20"

không những không lược được mà chẳng xếp được nữa đấy nhé!

Còn hàm Function1 lại báo lỗi ở dòng này:

str = str & ", " & Tmp & IIf(Count > 1, "-" & (Tmp + Count - 1), "")

huuthang_bd xem lại thử nhé!
 
Upvote 0
Với bài này tôi muốn các bạn vận dụng CreateObject("MSScriptControl.ScriptControl") để sắp xếp dãy số, tuy nó chẳng mới mẽ gì, nhưng ít thấy ai sử dụng, nó không có vòng lặp nào cả, nhưng đảm bảo sắp xếp không sai tí nào cả. Còn ta dùng vòng lặp, chưa chắc đã đúng hết hoặc dùng rất nhiều vòng lặp để thực hiện.

Sau khi dùng nó, ta chỉ cần duyệt các số qua thêm 1 vòng lặp nữa thôi thì công việc đã hoàn tất rồi.

Đây là đáp án của mình:

[GPECODE=vb]

Function SummarySerries(ByVal SerStr As String, Optional ByVal Unique As Boolean = True) As String
Dim StrSplit As Variant, _
i As Long, LenTmp As Long, _
Item As String, Tmp As String

SerStr = Replace(SerStr, " ", "")
''SAP XEP LAI DAY SO TU NHO DEN LON:
SerStr = "('" & SerStr & "').split(',').sort(function(a,b){return(a-b)}).join(',')"
With CreateObject("MSScriptControl.ScriptControl")
.Language = "JavaScript"
StrSplit = Split(.Eval(SerStr), ",")
End With

If Unique Then
''LUOC SO DUY NHAT:
For i = 0 To UBound(StrSplit)
Item = StrSplit(i)
If Item <> Tmp Then
If Tmp = "" Then
SummarySerries = SummarySerries & Item
Else
If Item - Tmp = 1 Then
SummarySerries = Replace(SummarySerries, "-" & Tmp, "") & "-" & Item
Else
SummarySerries = SummarySerries & ", " & Item
End If
End If
End If
Tmp = Item
Next
Else
''LUOC SO VAN DUY TRI SO TRUNG:
For i = 0 To UBound(StrSplit)
Item = StrSplit(i)
If Tmp = "" Then
SummarySerries = SummarySerries & Item
Else
If Item - Tmp = 1 Then
If InStr(Right(SummarySerries, Len(Tmp) + 1), "-") Then
LenTmp = Len(SummarySerries) - Len(Tmp) - 1
SummarySerries = Left(SummarySerries, LenTmp) & "-" & Item
Else
SummarySerries = SummarySerries & "-" & Item
End If
Else
SummarySerries = SummarySerries & ", " & Item
End If
End If
Tmp = Item
Next
End If
End Function


[/GPECODE]


Thủ tục:

Mã:
Sub XulyDaySo()
    Dim SerStr As String
    SerStr = "1,9,1,2,1,8,16,,,,4,3,11,11,9 ,,, ,5,11,12,13,,,,16,15,20,15,14,10,7,20"
    Debug.Print SummarySerries(SerStr)      'Luoc duy nhat
    Debug.Print SummarySerries(SerStr, 0)   'Khong duy nhat
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Đây là đáp án của mình:

[GPECODE=vb]

Function SummarySerries(ByVal SerStr As String, Optional ByVal Unique As Boolean = True) As String
Dim StrSplit As Variant, _
i As Long, LenTmp As Long, _
Item As String, Tmp As String

SerStr = Replace(SerStr, " ", "")
''SAP XEP LAI DAY SO TU NHO DEN LON:
SerStr = "('" & SerStr & "').split(',').sort(function(a,b){return(a-b)}).join(',')"
With CreateObject("MSScriptControl.ScriptControl")
.Language = "JavaScript"
StrSplit = Split(.Eval(SerStr), ",")
End With

[/CODE]
1 like :-= cho Đoạn code : sắp xếp các số trong chuỗi từ lớn đến nhỏ, không cần dùng vòng lặp !
--> <---

Nhưng mà tại sao em gõ createObject("MSScriptControl.ScriptControl") --> lỗi ActiveX components can't create object
--> điều kiện sử dụng là gì vậy anh ? em dùng win 8 64 bits

Cũng lạ thật, mặc dù em References vào microsoft script control 1.0 và sửa thành "with new scriptcontrol" mà vẫn báo lỗi
không lẽ là do cái thằng script control này đang nằm ở thư mục C:\Window\sýsWOW64\mmscript.ocx
 
Lần chỉnh sửa cuối:
Upvote 0
1 like :-= cho Đoạn code : sắp xếp các số trong chuỗi từ lớn đến nhỏ, không cần dùng vòng lặp !
--> <---

Nhưng mà tại sao em gõ createObject("MSScriptControl.ScriptControl") --> lỗi ActiveX components can't create object
--> điều kiện sử dụng là gì vậy anh ? em dùng win 8 64 bits

Tôi không biết, bởi tôi chưa bao giờ xài Win 64bit cả! Có thể phải khác với 32bit chứ nhỉ?
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi không biết, bởi tôi chưa bao giờ xài Win 64bit cả! Có thể phải khác với 32bit chứ nhỉ?
vì Ram em 4G nên em mới cài 64 bits, em vừa ktra : win 64 là C:\Window\sýsWOW64\mmscript.ocx, còn 32 bits hình như là C:\Window\system32\mmscript.ocx , để em google thử xem ntn ?

ặc vừa search đã thấy :
[NOTE1]The msscript component was not ported to 64 bit. It's a legacy component and MS chose not to put the effort into migrating it to 64 bit. You'll simply need to find another way to do whatever it is you do with that component.[/NOTE1]

Translate google :
[NOTE1]Thành phần msscript không được chuyển đến 64 bit. Đó là một phần di sản và MS đã quyết định không đặt các nỗ lực vào di chuyển nó đến 64 bit. Bạn chỉ đơn giản là sẽ cần phải tìm một cách khác để làm bất cứ điều gì bạn làm với thàn[/NOTE1]

** Lại phải suy nghĩ về vụ Ram 4G nên cài 32 bits hay 64 bits
+-+-+-+ và hình như cả DAO cũng không chạy trên 64bits !
 
Lần chỉnh sửa cuối:
Upvote 0
vì Ram em 4G nên em mới cài 64 bits, em vừa ktra : win 64 là C:\Window\sýsWOW64\mmscript.ocx, còn 32 bits hình như là C:\Window\system32\mmscript.ocx , để em google thử xem ntn ?

[NOTE1]----- Original Message -----From: "Doug Lee" <doug.lee@xxxxxxxxxxxxxxxx>
To: <jawsscripts@xxxxxxxxxxxxx>
Sent: Saturday, April 20, 2013 11:54 PM
Subject: [jawsscripts] Re: CreateObject on 64 bit sistem

CreateObject functions should be able to work on 64-bit Windows, but you would need a 64-bit version of the object you want, I think. Some objects don't come in that flavor. For example, the MSScriptControl.ScriptControl object was, to my knowledge, never made available in a 64-bit environment.

On Sat, Apr 20, 2013 at 11:51:09PM +0200, Dragan Miljojcic wrote:
Hello,

Has anyone successfully used the Jaws function "CreateObjectEx" on a 64 bit system. It seems that Jaws14 on 64 bit system, do not create an object, while the same Jaws script works on 32 bit system. Do you have any experience with this. I will be very grateful for any response.

Best regards,
Dragan.[/NOTE1]
 
Upvote 0
Với bài này tôi muốn các bạn vận dụng CreateObject("MSScriptControl.ScriptControl") để sắp xếp dãy số, tuy nó chẳng mới mẽ gì, nhưng ít thấy ai sử dụng, nó không có vòng lặp nào cả,

Sau khi dùng nó, ta chỉ cần duyệt các số qua thêm 1 vòng lặp nữa thôi thì công việc đã hoàn tất rồi.

Tôi không hiểu bạn khoe cái "không dùng vòng lặp" để làm gì nhỉ? Một đằng là tự viết, một đằng là dùng "đồ" của người khác.

Thế nếu bạn hungpecc1 sửa lại chút code rồi viết thành DLL nào đó rồi sau đó tôi dùng SUB của bạn ấy thì sao? Chả nhẽ tôi sẽ nói: "không dùng vòng lặp"? Thậm chí tôi còn hét lên: Thậm chí không cần "chỉ cần duyệt các số qua thêm 1 vòng lặp nữa thôi thì công việc đã hoàn tất rồi" mà có luôn "công việc đã hoàn tất"?

Nếu công việc bắt buộc phải "đóng đinh" thì phải đóng đinh, thế thôi. Bạn không phải đóng đinh chẳng qua là bạn "mượn" ai đó đóng định hộ bạn mà thôi. Cũng có thể bạn và không ai đóng định nhưng lúc đó thì để làm công việc bạn phải "vặn vít". Bạn không vặn thì có nghĩa là bạn "mượn" ai đó vặn. Mà bạn đừng khoe là không phải đóng đinh nhé. Vì lúc đó tôi sẽ khoe là tôi không phải vặn vít như bạn.

Công việc không tự nhiên sinh ra và cũng không tự nhiên mất đi. Nó chỉ "nhẩy" từ người này sang người khác. Bạn học định luật bảo toàn công việc chưa? He he.
 
Upvote 0
Tôi không hiểu bạn khoe cái "không dùng vòng lặp" để làm gì nhỉ? Một đằng là tự viết, một đằng là dùng "đồ" của người khác.

Thế nếu bạn hungpecc1 sửa lại chút code rồi viết thành DLL nào đó rồi sau đó tôi dùng SUB của bạn ấy thì sao? Chả nhẽ tôi sẽ nói: "không dùng vòng lặp"? Thậm chí tôi còn hét lên: Thậm chí không cần "chỉ cần duyệt các số qua thêm 1 vòng lặp nữa thôi thì công việc đã hoàn tất rồi" mà có luôn "công việc đã hoàn tất"?

Nếu công việc bắt buộc phải "đóng đinh" thì phải đóng đinh, thế thôi. Bạn không phải đóng đinh chẳng qua là bạn "mượn" ai đó đóng định hộ bạn mà thôi. Cũng có thể bạn và không ai đóng định nhưng lúc đó thì để làm công việc bạn phải "vặn vít". Bạn không vặn thì có nghĩa là bạn "mượn" ai đó vặn. Mà bạn đừng khoe là không phải đóng đinh nhé. Vì lúc đó tôi sẽ khoe là tôi không phải vặn vít như bạn.

Công việc không tự nhiên sinh ra và cũng không tự nhiên mất đi. Nó chỉ "nhẩy" từ người này sang người khác. Bạn học định luật bảo toàn công việc chưa? He he.

Đã nói không dùng vòng lặp trong VBA rồi mà Thầy, thử xem, nếu dùng hàm InStr để tìm 1 hoặc nhiều ký tự nào đó trong một chuỗi, thì bản thân nó có dùng vòng lặp không? Ai đảm bảo rằng nó sẽ không có đằng sau "hậu trường"? Tuy nhiên, khi người sử dụng nó, có quyền nói rằng "tôi không dùng vòng lặp" trong code của tôi. Vậy thôi à.
 
Upvote 0
Đã nói không dùng vòng lặp trong VBA rồi mà Thầy, thử xem, nếu dùng hàm InStr để tìm 1 hoặc nhiều ký tự nào đó trong một chuỗi, thì bản thân nó có dùng vòng lặp không? Ai đảm bảo rằng nó sẽ không có đằng sau "hậu trường"? Tuy nhiên, khi người sử dụng nó, có quyền nói rằng "tôi không dùng vòng lặp" trong code của tôi. Vậy thôi à.

Bạn là người đố, bạn có thể ra điều kiện. Tôi đã đọc các bài viết của bạn và không thấy có chỗ nào ra điều kiện: "không dùng vòng lặp trong VBA"

Hay tôi sơ ý không nhìn thấy?
 
Upvote 0
Bạn là người đố, bạn có thể ra điều kiện. Tôi đã đọc các bài viết của bạn và không thấy có chỗ nào ra điều kiện: "không dùng vòng lặp trong VBA"

Hay tôi sơ ý không nhìn thấy?

Oh, thật ra em không nhấn mạnh điều này, bởi vì mỗi người có mỗi thuật toán để thực hiện, những người làm đúng yêu cầu thì đã là có đáp án đúng. Điều em mong đợi rằng qua nhiều đáp án, sẽ có nhiều cách để thực hiện yêu cầu đó, thông qua đó, em sẽ được học thêm nhiều.

Kinh nghiệm cho em thấy rằng "Hãy cho rồi sẽ nhận", nên em sẳn sàng gửi tặng những gì em học được và hiểu biết được lên diễn đàn, và sau đó em biết em sẽ được nhiều người góp ý, chỉnh sửa và hoàn thiện ý tưởng của em.
 
Upvote 0
Làm đại 2 cách cách nào được thì lấy :D.
Phương án 1
PHP:
Function Function1(Str As String) As String
Dim Arr, i As Long, j As Long, Tmp, Count As Long
Arr = Split(Str, ", ")
For i = LBound(Arr) To UBound(Arr)
    For j = i + 1 To UBound(Arr)
        If CLng(Arr(j)) < CLng(Arr(i)) Then
            Tmp = Arr(j):   Arr(j) = Arr(i):    Arr(i) = Tmp
        End If
    Next
Next
Tmp = Arr(LBound(Arr)):    Count = 1:   Str = ""
For i = LBound(Arr) + 1 To UBound(Arr)
    If CLng(Arr(i)) = Tmp + Count Then
        Count = Count + 1
    Else
        Str = Str & ", " & Tmp & IIf(Count > 1, "-" & (Tmp + Count - 1), "")
        Tmp = CLng(Arr(i))
        Count = 1
    End If
Next
Str = Str & ", " & Tmp & IIf(Count > 1, "-" & (Tmp + Count - 1), "")
Function1 = Replace(Str, ", ", "", 1, 1)
End Function

Qua bài này, tôi quan tâm đến dòng này:

If CLng(Arr(j)) < CLng(Arr(i)) Then

Thay vì với CLng hay CDbl, thì tôi lại nghĩ dùng Val.

Lý do: Với Val("") hay Val("abc") nó trả về giá trị 0, như thế, vẫn so sánh được, còn CLng hay CDbl nó lại báo lỗi.

Theo các bạn, tôi dùng Val có tốt hơn không?
 
Upvote 0
Tôi không hiểu bạn khoe cái "không dùng vòng lặp" để làm gì nhỉ? Một đằng là tự viết, một đằng là dùng "đồ" của người khác.

Thế nếu bạn hungpecc1 sửa lại chút code rồi viết thành DLL nào đó rồi sau đó tôi dùng SUB của bạn ấy thì sao? Chả nhẽ tôi sẽ nói: "không dùng vòng lặp"? Thậm chí tôi còn hét lên: Thậm chí không cần "chỉ cần duyệt các số qua thêm 1 vòng lặp nữa thôi thì công việc đã hoàn tất rồi" mà có luôn "công việc đã hoàn tất"?

Nếu công việc bắt buộc phải "đóng đinh" thì phải đóng đinh, thế thôi. Bạn không phải đóng đinh chẳng qua là bạn "mượn" ai đó đóng định hộ bạn mà thôi. Cũng có thể bạn và không ai đóng định nhưng lúc đó thì để làm công việc bạn phải "vặn vít". Bạn không vặn thì có nghĩa là bạn "mượn" ai đó vặn. Mà bạn đừng khoe là không phải đóng đinh nhé. Vì lúc đó tôi sẽ khoe là tôi không phải vặn vít như bạn.

Công việc không tự nhiên sinh ra và cũng không tự nhiên mất đi. Nó chỉ "nhẩy" từ người này sang người khác. Bạn học định luật bảo toàn công việc chưa? He he.

Chuẩn bác siwtom ah,

Đây là sai lầm ngớ ngẩn nhất của nhiều người sử dụng - cứ tưởng đó không phải dùng vòng lặp (khi sử dụng công cụ khác) - ví như dùng máy xay sinh tốt thay vì dùng dao cắt rùi nghền ... sẽ nghĩ nó không cắt không chém ( có khi còn cắt chém nhiều hơn nhiều năng lượng hơn). Vì thế không thể nói là không dùng vòng lặp dù là Instr hay là scripts nào đó

Vì thế, đôi khi ta cần rèn luyện từ bước cơ bản, và hiểu bản chất của các công cụ chứ không phải nói sai từ như thế dẫn đến nhiều người hiểu lầm
 
Upvote 0
Hỏi để học:

Chào các bạn,

Nếu như không sắp xếp kiểu Script và cũng không sắp xếp kiểu như bạn huuthang_bd (code dưới) thì còn kiểu sắp xếp chuỗi nào nữa không ạ?

Mã:
[COLOR=#0000BB][FONT=monospace][I]Arr [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Split[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Str[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I], [/I][/FONT][/COLOR][COLOR=#DD0000][FONT=monospace][I]", "[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
For [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]LBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]To UBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
    For [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]+ [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]1 To UBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
        If [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]CLng[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])) < [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]CLng[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])) [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Then
            Tmp [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]):   [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) = [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]):    [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) = [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Tmp
        End [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]If
    [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Next
Next[/I][/FONT][/COLOR]
 
Upvote 0
Chào các bạn,

Nếu như không sắp xếp kiểu Script và cũng không sắp xếp kiểu như bạn huuthang_bd (code dưới) thì còn kiểu sắp xếp chuỗi nào nữa không ạ?

Mã:
[COLOR=#0000BB][FONT=monospace][I]Arr [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Split[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Str[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I], [/I][/FONT][/COLOR][COLOR=#DD0000][FONT=monospace][I]", "[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
For [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]LBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]To UBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
    For [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]+ [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]1 To UBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
        If [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]CLng[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])) < [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]CLng[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])) [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Then
            Tmp [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]):   [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) = [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]):    [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) = [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Tmp
        End [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]If
    [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Next
Next[/I][/FONT][/COLOR]


Có một cách hiệu quả, đó là:

1) Cắt chuỗi về mảng 1 chiều

2) Gán mảng đó vào sheet sau khi đổi chiều (Transpose)

3) Dùng công cụ SORT của sheet sắp xếp lại dữ liệu

4) Gán ngược giá trị về mảng rồi chuyển mảng về chuỗi.

Mã:
Sub NoiChuoi()

    Dim Chuoi As String, Str As String
    Dim SplArr, StrSplArr(), i As Long, u As Long
    Chuoi = "10,9,8,5,6,7,8,3,4,6,7,9,10,1,11,33"
    SplArr = Split(Chuoi, ",")
    
    u = UBound(SplArr) + 1
    
    With Range("F1").Resize(u)
        .Value = WorksheetFunction.Transpose(SplArr)
        .Sort [F1], xlAscending
        SplArr = .Value
    End With
    
    For i = 2 To u
        Str = Str & "," & SplArr(i, 1)
    Next


    Str = SplArr(1, 1) & Str
    
    Debug.Print Str
    
[COLOR=#008000]'    ReDim StrSplArr(1 To u)[/COLOR]
[COLOR=#008000]'    For i = 1 To u[/COLOR]
[COLOR=#008000]'        StrSplArr(i) = SplArr(i, 1)[/COLOR]
[COLOR=#008000]'    Next[/COLOR]
[COLOR=#008000]'    Chuoi = Join(StrSplArr, ",")[/COLOR]
[COLOR=#008000]'    Debug.Print Chuoi[/COLOR]


End Sub

Nhưng chúng ta phải làm như vậy sao? Nếu mà là hàm thì Sheet ở đâu ra nhỉ? Tạo ra? Lỡ phần tử bên trong lớn hơn số hàng thì sao?

"Cơ bản" lắm đó, nhưng cũng kỳ lắm đó!
 
Upvote 0
Chào các bạn,

Nếu như không sắp xếp kiểu Script và cũng không sắp xếp kiểu như bạn huuthang_bd (code dưới) thì còn kiểu sắp xếp chuỗi nào nữa không ạ?

Mã:
[COLOR=#0000BB][FONT=monospace][I]Arr [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Split[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Str[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I], [/I][/FONT][/COLOR][COLOR=#DD0000][FONT=monospace][I]", "[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
For [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]LBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]To UBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
    For [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]+ [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]1 To UBound[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])
        If [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]CLng[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])) < [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]CLng[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I])) [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Then
            Tmp [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]= [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]):   [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]j[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) = [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]):    [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Arr[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]([/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]i[/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]) = [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Tmp
        End [/I][/FONT][/COLOR][COLOR=#007700][FONT=monospace][I]If
    [/I][/FONT][/COLOR][COLOR=#0000BB][FONT=monospace][I]Next
Next[/I][/FONT][/COLOR]
Theo em nếu đã đưa được chuỗi về mảng Arr= Split(str,",") ta có thể dùng các thuật toán sắp xếp mảng thông dụng :
* Cách sắp xếp như của a Huuthang_bd hình như được gọi là Selection Sort
* Theo kiểu Quick Sort thì như vậy :
[GPECODE=vb]
Sub quicksort(subArr(), ByVal L As Long, ByVal U As Long)
Dim i As Long, j As Long
Dim pivot, TG
If L >= U Then Exit Sub
i = L: j = U
pivot = Int(Rnd() * (j - i + 1) + i)
Do
While subArr(i) < subArr(pivot)
i = i + 1
Wend
While subArr(j) > subArr(pivot)
j = j - 1
Wend
If i <= j Then
TG = subArr(i): subArr(i) = subArr(j): subArr(j) = TG
i = i + 1
j = j - 1
End If
Loop Until i > j
quicksort subArr, L, j
quicksort subArr, i, U
End Sub
[/GPECODE]
Kiểm tra :
Mã:
Sub test()
    Dim arr()
    Dim item
    arr = Array(1, 3, 5, 8, 97, 4, 5, 6)
    quicksort arr, LBound(arr), UBound(arr)
    For Each item In arr
        Debug.Print item
    Next
End Sub
* Hôm qua mới vọc thêm vụ Distribution count sorting :sắp xếp bằng phép đếm phân phối :
Cách thức hoạt động của thuật toán
- Ta xây dựng dãy c(1),c(2),...,c(M) trong đó c(i) là số lần xuất hiện của số i trong dãy cần sắp xếp.
Vd: Với dãy: 1,5,4,2,1,4,7,5,5,8 thì: c(1)=2; c(2)=1,c(4)=2; c(5)=3; c(7)=1; c(8)=1
- Dựa vào c(i), ta có thể biết được giá trị i sẽ nằm từ vị trí nào đến vị trí nào trong dãy đã sắp xếp:
Vd: Với dãy trên sau khi đã sắp xếp là: 1,1,2,4,4,5,5,5,7,8
++++++++++Giá trị 1 đứng ở vị trí từ 1 -> c(1) [tức từ 1 -> 2]
++++++++++Giá trị 2 đứng ở vị trí từ c(1)+1 -> c(1) + c(2) [tức là từ 3->3]
++++++++++Giá trị i đứng ở vị trí từ c(1)+c(2)+c(3)+...+c(i-1)+1 -> c(1)+c(2)+c(3)+...+c(i-1)+c(i)
- Sau đó dựa vào dãy c này ta dựng nên dãy t là dãy đã được sắp xếp từ dãy a và gán dãy t vào dãy a.
Mã:
[COLOR=#000080][FONT=monospace]Private[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Sub[/FONT][/COLOR][COLOR=#444444][FONT=monospace] DistributionCountingSort()[/FONT][/COLOR]
[COLOR=#000080][FONT=monospace]Dim[/FONT][/COLOR][COLOR=#444444][FONT=monospace] c(1 [/FONT][/COLOR][COLOR=#000080][FONT=monospace]To[/FONT][/COLOR][COLOR=#444444][FONT=monospace] M) [/FONT][/COLOR][COLOR=#000080][FONT=monospace]As[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Long[/FONT][/COLOR]
[COLOR=#000080][FONT=monospace]Dim[/FONT][/COLOR][COLOR=#444444][FONT=monospace] t(1 [/FONT][/COLOR][COLOR=#000080][FONT=monospace]To[/FONT][/COLOR][COLOR=#444444][FONT=monospace] N) [/FONT][/COLOR][COLOR=#000080][FONT=monospace]As[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Long[/FONT][/COLOR]
[COLOR=#000080][FONT=monospace]Dim[/FONT][/COLOR][COLOR=#444444][FONT=monospace] i [/FONT][/COLOR][COLOR=#000080][FONT=monospace]As[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Long[/FONT][/COLOR][COLOR=#444444][FONT=monospace], j [/FONT][/COLOR][COLOR=#000080][FONT=monospace]As[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Long[/FONT][/COLOR]
[COLOR=#000080][FONT=monospace]For[/FONT][/COLOR][COLOR=#444444][FONT=monospace] i = 1 [/FONT][/COLOR][COLOR=#000080][FONT=monospace]To[/FONT][/COLOR][COLOR=#444444][FONT=monospace] N[/FONT][/COLOR]
[COLOR=#444444][FONT=monospace]  c(a(i)) = c(a(i)) + 1 [/FONT][/COLOR][COLOR=#008000][FONT=monospace]'Đếm số lần xuất hiện của giá trị i trong dãy
[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Next[/FONT][/COLOR]
[COLOR=#000080][FONT=monospace]For[/FONT][/COLOR][COLOR=#444444][FONT=monospace] i = 2 [/FONT][/COLOR][COLOR=#000080][FONT=monospace]To[/FONT][/COLOR][COLOR=#444444][FONT=monospace] M[/FONT][/COLOR]
[COLOR=#444444][FONT=monospace]  c(i) = c(i - 1) + c(i) [/FONT][/COLOR][COLOR=#008000][FONT=monospace]'Tính vị trí cuối của mỗi giá trị trong dãy
[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Next[/FONT][/COLOR]
[COLOR=#000080][FONT=monospace]For[/FONT][/COLOR][COLOR=#444444][FONT=monospace] i = N [/FONT][/COLOR][COLOR=#000080][FONT=monospace]To[/FONT][/COLOR][COLOR=#444444][FONT=monospace] 1 [/FONT][/COLOR][COLOR=#000080][FONT=monospace]Step[/FONT][/COLOR][COLOR=#444444][FONT=monospace] -1[/FONT][/COLOR]
[COLOR=#444444][FONT=monospace]  j = a(i) [/FONT][/COLOR][COLOR=#008000][FONT=monospace]'Lấy ra giá trị của khóa a(i)
[/FONT][/COLOR][COLOR=#444444][FONT=monospace] t(c(j)) = a(i) [/FONT][/COLOR][COLOR=#008000][FONT=monospace]'biến c(j) sẽ chứa vị trí mà a(i) cần phải ở khi đã được sắp xếp, giá trị này sẽ được đưa vào đúng vị trí trong dãy t
[/FONT][/COLOR][COLOR=#444444][FONT=monospace] c(j) = c(j) - 1 [/FONT][/COLOR][COLOR=#008000][FONT=monospace]'đồng thời giảm giá trị của c(j) xuống 1 đơn vị để những giá trị sau sẽ được thêm vào trước vị trí trên.
[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Next[/FONT][/COLOR]
[COLOR=#000080][FONT=monospace]For[/FONT][/COLOR][COLOR=#444444][FONT=monospace] i = 1 [/FONT][/COLOR][COLOR=#000080][FONT=monospace]To[/FONT][/COLOR][COLOR=#444444][FONT=monospace] N[/FONT][/COLOR]
[COLOR=#444444][FONT=monospace]  a(i) = t(i) [/FONT][/COLOR][COLOR=#008000][FONT=monospace]'Gán toàn bộ giá trị của dãy t vào dãy a
[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Next[/FONT][/COLOR]
[COLOR=#000080][FONT=monospace]End[/FONT][/COLOR][COLOR=#000080][FONT=monospace]Sub[/FONT][/COLOR]

p/s : mà hình như chủ đề là " đố vui VBA " còn mấy cái vụ này không được gọi là "đố vui" roài , anh có thể rời bài ra topic " vui để đố " để không vi phạm nội quy :-=
 
Lần chỉnh sửa cuối:
Upvote 0
Theo em nếu đã đưa được chuỗi về mảng Arr= Split(str,",") ta có thể dùng các thuật toán sắp xếp mảng thông dụng :
* Cách sắp xếp như của a Huuthang_bd hình như được gọi là Selection Sort
* Theo kiểu Quick Sort thì như vậy
.....................

Một mảng được cắt ra từ chuổi thì nó có được bao nhiêu phần tử mà phải "đấu" về tốc độ
Có thể dùng System.Collections.ArrayList cho đơn giản.
Thí nghiệm xem:
Mã:
Sub Test()
  Dim str As String, arr, i As Long
  str = "10,9,8,5,6,7,8,3,4,6,7,9,10,1,11,33"
  arr = Split(str, ",")
  With CreateObject("System.Collections.ArrayList")
    For i = 0 To UBound(arr): .Add CLng(arr(i)): Next
    .Sort: arr = .ToArray
  End With
  MsgBox Join(arr, "-")
End Sub
------------------------------
p/s : mà hình như chủ đề là " đố vui VBA " còn mấy cái vụ này không được gọi là "đố vui" roài , anh có thể rời bài ra topic " vui để đố " để không vi phạm nội quy
biggrin.png
ĐỐ VUI tức là ĐỐ cái gì thật ĐƠN GIẢN nhưng ít ai nghĩ ra (đáp án bất ngờ)
Vậy nên bài này chẳng VUI tí nào
 
Upvote 0
Với chuỗi số đó, hướng 2 (hàm Function2) thì cho kết quả:

Kết quả = "1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15 ,14,10,7,20"

không những không lược được mà chẳng xếp được nữa đấy nhé!

Còn hàm Function1 lại báo lỗi ở dòng này:

str = str & ", " & Tmp & IIf(Count > 1, "-" & (Tmp + Count - 1), "")

huuthang_bd xem lại thử nhé!
Bạn hãy đưa dữ liệu đầu vào về dạng chuẩn dữ liệu ở bài đầu tiên bạn đố (tức là giữa các số được phân cách nhau bằng một dấu phẩy và một khoản trắng) thì bạn sẽ thấy.
 
Upvote 0
Mã:
Sub Test()
  Dim str As String, arr, i As Long
  str = "10,9,8,5,6,7,8,3,4,6,7,9,10,1,11,33"
  arr = Split(str, ",")
  With CreateObject("System.Collections.ArrayList")
    For i = 0 To UBound(arr): .Add CLng(arr(i)): Next
    .Sort: arr = .ToArray
  End With
  MsgBox Join(arr, "-")
End Sub

Nhân tiện nói về ArrayList, xin đố 1 câu: Code trên Sort từ nhỏ đến lớn. Vậy xin hỏi phải sửa code thế nào để sort ngược lại: Từ lớn đến nhỏ?
 
Upvote 0
Upvote 0
Nhân tiện nói về ArrayList, xin đố 1 câu: Code trên Sort từ nhỏ đến lớn. Vậy xin hỏi phải sửa code thế nào để sort ngược lại: Từ lớn đến nhỏ?
Cũng giống như thằng em kia:

Mã:
Function SortArraySystem2(SerStr As String) As String
    Dim str As String, arr, i As Long
    arr = Split(SerStr, ",")
    With CreateObject("System.Collections.ArrayList")
        For i = 0 To UBound(arr)
            .Add CLng(arr(i))
        Next
        .Sort
[COLOR=#ff0000][B]        .Reverse[/B][/COLOR]
        arr = .ToArray
    End With
    SortArraySystem2 = Join(arr, "-")
End Function
 
Upvote 0
Một mảng được cắt ra từ chuổi thì nó có được bao nhiêu phần tử mà phải "đấu" về tốc độ
Có thể dùng System.Collections.ArrayList cho đơn giản.
Thí nghiệm xem:
Mã:
Sub Test()
  Dim str As String, arr, i As Long
  str = "10,9,8,5,6,7,8,3,4,6,7,9,10,1,11,33"
  arr = Split(str, ",")
  With CreateObject("System.Collections.ArrayList")
    For i = 0 To UBound(arr): .Add CLng(arr(i)): Next
    .Sort: arr = .ToArray
  End With
  MsgBox Join(arr, "-")
End Sub
------------------------------

ĐỐ VUI tức là ĐỐ cái gì thật ĐƠN GIẢN nhưng ít ai nghĩ ra (đáp án bất ngờ)
Vậy nên bài này chẳng VUI tí nào

Mã:
Function SortArrayScript(SerStr As String) As String
    SerStr = "('" & SerStr & "').split(',').sort(function(a,b){return (a-b)}).join(',')" ' & ".reverse()" 'if DESC
    With CreateObject("MSScriptControl.ScriptControl")
        .Language = "JavaScript"
        SortArrayScript = .Eval(SerStr)
    End With
End Function


Function SortArraySystem(SerStr As String) As String
    Dim str As String, arr, i As Long
    arr = Split(SerStr, ",")
    With CreateObject("System.Collections.ArrayList")
        For i = 0 To UBound(arr)
            .Add CLng(arr(i))
        Next
        .Sort: arr = .ToArray
    End With
    SortArraySystem = Join(arr, "-")
End Function

Xét về tốc độ, thì 2 thằng em này cũng ngang ngang nhau, nếu dùng For ... Next do mình xử lý chuỗi thì có mà chờ dài cổ, tôi đã thử code của huuthang_bd với 1,000 mục cho ra thời gian đâu có bao nhiêu: 114 giây! Trong khi đó, với 60,000 mục thì 2 thằng em trên xử lý trong vòng 2 giây.

Thế cho nên đừng ai vỗ ngực xưng tên tôi hay và chê người ta ngớ ngẫn, mà hãy học thêm và biết chọn lọc tinh hoa của người khác mà ứng dụng vô công việc của mình. Bạn có giỏi thì cứ cắt bằng tay đi rồi nghiền nát, còn tôi thì dùng máy xay sinh tố vậy!


''===================================

Suy cho cùng thì tôi thích cách mà Thầy NDU giới thiệu hơn: System.Collections.ArrayList

Nó dễ hiểu, dễ hình dung, nó đơn giản và không cầu kỳ, không như
MSScriptControl.ScriptControl cấu trúc thật sự khó hiểu và không thân thiện lắm.

Cám ơn Thầy.
 
Lần chỉnh sửa cuối:
Upvote 0
Thế cho nên đừng ai vỗ ngực xưng tên tôi hay và chê người ta ngớ ngẫn, mà hãy học thêm và biết chọn lọc tinh hoa của người khác mà ứng dụng vô công việc của mình. Bạn có giỏi thì cứ cắt bằng tay đi rồi nghiền nát, còn tôi thì dùng máy xay sinh tố vậy!

Nói AI vậy trời? ??? ??? ???
----------------
Suy cho cùng thì tôi thích cách mà Thầy NDU giới thiệu hơn: System.Collections.ArrayList

Nó dễ hiểu, dễ hình dung, nó đơn giản và không cầu kỳ, không như
MSScriptControl.ScriptControl cấu trúc thật sự khó hiểu và không thân thiện lắm.

Cám ơn Thầy.
Thích thì tặng luôn:
Mã:
Function Sort1DArray(ByVal SourceArray, ByVal Order As Boolean)
  Dim i As Long, aTmp
  On Error Resume Next
  aTmp = SourceArray
  With CreateObject("System.Collections.ArrayList")
    For i = LBound(aTmp) To UBound(aTmp): .Add aTmp(i): Next
    .Sort
    If Order = False Then .Reverse
    Sort1DArray = .ToArray()
  End With
End Function
 
Upvote 0
Nói AI vậy trời? ??? ??? ???
----------------

Thích thì tặng luôn:
Mã:
Function Sort1DArray(ByVal SourceArray, ByVal Order As Boolean)
  Dim i As Long, aTmp
  On Error Resume Next
  aTmp = SourceArray
  With CreateObject("System.Collections.ArrayList")
    For i = LBound(aTmp) To UBound(aTmp): .Add aTmp(i): Next
    .Sort
    If Order = False Then .Reverse
    Sort1DArray = .ToArray()
  End With
End Function


Sẳn đây em cũng có tham khảo một số thủ tục mà CreateObject("System.Collections.ArrayList") hoạt động, những bạn chưa biết nhiều về nó thì tham khảo chung luôn:

[GPECODE=vb] Option Explicit
Sub ptest()
'http://www.robvanderwoude.com/vbstech.php#Data
'http://www.thecodecage.com/forumz/showthread.php?p=1055000938#post1055000938
'this code creates and populates an ArrayList

Dim myArrayList As Object, myArrayList2 As Object
Dim xItem, myrange

Set myArrayList = CreateObject("System.Collections.ArrayList")
myArrayList.Add "Kyle"
myArrayList.Add "123"
myArrayList.Add "C"
myArrayList.Add "snb"
myArrayList.Add "pike"

'result to immediate window
Debug.Print Join(myArrayList.toarray(), Chr(10))

' copy / clone ArrayList
Set myArrayList2 = myArrayList.Clone

'Now, to add an element and sort the ArrayList, all we need to do is:
'add the new element to the ArrayList
myArrayList.Add "Z"

'remove the new element to the ArrayList
myArrayList.Remove "C"

'result to immediate window
Debug.Print Join(myArrayList.toarray(), Chr(10))

'result to immediate window
Debug.Print "List Has C " & myArrayList.Contains("C")
Debug.Print "List Has Z " & myArrayList.Contains("Z")

'result to immediate window - count elements and capacity
Debug.Print "Size : " & myArrayList.Count
Debug.Print "Capacity : " & myArrayList.Capacity

'trim blank elements from the ArrayList
myArrayList.TrimToSize

'result to immediate window - count elements and capacity
Debug.Print "Size : " & myArrayList.Count
Debug.Print "Capacity : " & myArrayList.Capacity

'sort the ArrayList
myArrayList.Sort

'result to immediate window
Debug.Print Join(myArrayList.toarray(), Chr(10))

' reverse the ArrayList
myArrayList.Reverse

'result to immediate window
Debug.Print Join(myArrayList.toarray(), Chr(10))

' copy / clone ArrayList2 result to immediate window
Debug.Print Join(myArrayList2.toarray(), Chr(10))

'toarray transfer ArrayList to results to worksheet
Range("B1").Resize(myArrayList.Count) = Application.Transpose(myArrayList.toarray())
Range("C1").Resize(1, myArrayList.Count) = myArrayList.toarray()

Set myArrayList = Nothing
Set myArrayList2 = Nothing
End Sub[/GPECODE]

[GPECODE=vb]Sub Queuelist() With CreateObject("System.Collections.Queue")
.Enqueue "Kyle"
.Enqueue "123"
.Enqueue "snb"
.Enqueue "pike"
.Enqueue "Simon"

Debug.Print Join(.Toarray(), Chr(10))

.Dequeue

Debug.Print .Peek

Debug.Print Join(.Toarray(), Chr(10))

Range("A1").Resize(.Count) = Application.Transpose(.Toarray())
Range("C1").Resize(1, .Count) = .Toarray()

End With

End Sub

Sub Stacklist()
With CreateObject("System.Collections.Stack")
.Push "Kyle"
.Push "123"
.Push "snb"
.Push "pike"
.Push "Simon"

Debug.Print Join(.Toarray(), Chr(10))

.pop

Debug.Print .Peek

Debug.Print Join(.Toarray(), Chr(10))

Range("A1").Resize(.Count) = Application.Transpose(.Toarray())
Range("C1").Resize(1, .Count) = .Toarray()

End With

End Sub [/GPECODE]

[GPECODE=vb]'http://www.robvanderwoude.com/vbstech.php#Data
'http://www.thecodecage.com/forumz/showthread.php?p=1055000938#post1055000938

Dim objSortedList As Object
Dim objList2 As Object
Dim i As Integer

Set objSortedList = CreateObject("System.Collections.Sortedlist")

objSortedList.Add "First", "AAAA"
objSortedList.Add "Second", "!"
objSortedList.Add "Third", "CCCC"
objSortedList.Add "Fourth", ","

Debug.Print objSortedList.IndexOfKey("First")
Debug.Print objSortedList.IndexOfValue("AAAA")
Debug.Print objSortedList.IndexOfKey("Second")
Debug.Print objSortedList.IndexOfValue("!")
Debug.Print objSortedList.IndexOfKey("Third")
Debug.Print objSortedList.IndexOfValue("CCCC")
Debug.Print objSortedList.IndexOfKey("Fourth")
Debug.Print objSortedList.IndexOfValue(",")


For i = 0 To objSortedList.Count - 1
Debug.Print objSortedList.GetKey(i) & vbTab & objSortedList.GetByIndex(i)

Next
'This is the resulting output:

'First Hello
'Fourth !
'Second ,
'Third world
'Note how the list is automatically sorted by keys; it is not possible to sort the list by values.

'Like ArrayLists, SortedLists have Count and Capacity properties, and a TrimToSize method, demonstrated in the following code:

Debug.Print "Size : " & objSortedList.Count
Debug.Print "Capacity : " & objSortedList.Capacity


objSortedList.TrimToSize

Debug.Print "Size : " & objSortedList.Count
Debug.Print "Capacity : " & objSortedList.Capacity
'This will result in the following output:

'Size : 4
'Capacity : 16

'Size : 4
'Capacity : 4
'Cloning a SortedList is a piece of cake:
Dim xxxx
Set objList2 = objSortedList.Clone
Debug.Print "Sorted List Key(1) = " & objSortedList.GetKey(1)
Debug.Print "Cloned List Key(1) = " & objList2.GetKey(1)
'The result:


'Sorted List Key(1) = Fourth
'Cloned List Key(1) = Fourth
Set objList2 = Nothing
Set objSortedList = Nothing
End Sub [/GPECODE]

[GPECODE=vb]Option Explicit Sub System_Collections_ArrayList()

' Reference Library mscorlib

Dim ArrayListOne As Object, ArrayListTwo As ArrayList, ArrayListThree As Object, ArrayListFour As ArrayList

Set ArrayListOne = CreateObject("System.Collections.ArrayList") ' method with out Reference library
Set ArrayListTwo = New ArrayList 'Can use this method after loading Reference Library mscorlib
Set ArrayListThree = CreateObject("System.Collections.ArrayList") ' method with out Reference library
Set ArrayListFour = New ArrayList 'Can use this method after loading Reference Library mscorlib

ArrayListOne.Add "A"
ArrayListOne.Add "B"
ArrayListOne.Add "D"
ArrayListOne.Insert 2, "C"
ArrayListOne.Insert 2, "C"
ArrayListOne.Add "E"
ArrayListOne.Add "C"
ArrayListOne.Add "F"
ArrayListOne.Add "G"

Debug.Print ArrayListOne.Item(3)
Debug.Print ArrayListOne.Contains("C")
Debug.Print ArrayListOne.IndexOf_2("C", 0, 4)
Debug.Print ArrayListOne.Contains("H")
Debug.Print ArrayListOne.LastIndexOf("C")

ArrayListOne.Remove "C"
ArrayListOne.RemoveAt 5

With ArrayListTwo
.Add "1"
.Add "2"
.Add "3"
.Add "4"
.Add "5"
End With

ArrayListThree.Add "EE"
ArrayListThree.Add "CC"
ArrayListThree.Add "BB"
ArrayListThree.Insert 2, "DD"
ArrayListThree.Add "AA"

ArrayListOne.Addrange ArrayListThree
ArrayListOne.insertRange 6, ArrayListTwo
ArrayListOne.Addrange ArrayListTwo
ArrayListOne.RemoveRange 6, 5
ArrayListOne.Reverse_2 7, 5

ArrayListOne.TrimToSize

Debug.Print Join(ArrayListOne.toarray(), Chr(10))
Debug.Print ArrayListOne.ToString

Range("A10").Resize(ArrayListOne.Capacity) = Application.Transpose(ArrayListOne.toarray())
Range("C10").Resize(, ArrayListOne.Count) = ArrayListOne.toarray()

With ArrayListOne

Debug.Print .binarysearch_2("CC")

.Sort

Debug.Print .binarysearch_2("CC")

.Reverse

Debug.Print Join(.toarray(), Chr(10))
Debug.Print .GetHashCode

End With

Debug.Print Join(ArrayListFour.toarray(), Chr(10))

ArrayListFour.Add "pike"
ArrayListFour.Add "Japan Dave"
ArrayListFour.Add "Kyle123"
ArrayListFour.Add "snb"

ArrayListOne.SetRange 5, ArrayListFour

Debug.Print Join(ArrayListOne.toarray(), Chr(10))

Set ArrayListOne = Nothing
Set ArrayListTwo = Nothing
Set ArrayListThree = Nothing
Set ArrayListFour = Nothing

End Sub [/GPECODE]
 
Lần chỉnh sửa cuối:
Upvote 0
Thế cho nên đừng ai vỗ ngực xưng tên tôi hay và chê người ta ngớ ngẫn, mà hãy học thêm và biết chọn lọc tinh hoa của người khác mà ứng dụng vô công việc của mình. Bạn có giỏi thì cứ cắt bằng tay đi rồi nghiền nát, còn tôi thì dùng máy xay sinh tố vậy!

Bạn cố tình không hiểu vodoi2x nói gì rồi. Tôi nói cố tình vì tôi biết là bạn hiểu. Ý của vodoi2x chỉ là bạn có thể chặt chém hoa quả nhưng cũng có thể dùng máy xay sinh tố. Nhưng không có nghĩa là dùng máy xay sinh tố thì không có hiện tượng chặt chém. Chưa cần mở xem, chưa cần dùng lần nào mà chỉ đọc tên máy cũng đã biết là "chặt chém" có sẩy ra.
Bạn vodoi2x không nói rằng không nên dùng máy xay sinh tố, cũng không nói rằng dùng máy kém hơn hay bất cứ ý nào khác.

Bạn nói là bạn không phải làm A - hàm ý là người khác phải làm A - thì tôi nói rằng: vì bạn dùng B mà B làm A thay bạn. Người khác làm A chẳng qua là họ tự làm. Bạn nói tiếp là bạn đã ra điều kiện là "không được làm A" cơ mà. Nhưng tôi thường đọc rất kỹ bài của người khác nên tôi biết là bạn không ra điều kiện. Tôi lại chỉ ra. Chả nhẽ bạn mất bình tĩnh vì thế sao?

Cả tôi và vodoi2x không nói gì để bạn có thể viết ra những dòng đỏ đỏ. Bình tĩnh lại đi.
 
Lần chỉnh sửa cuối:
Upvote 0
.........

Thế cho nên đừng ai vỗ ngực xưng tên tôi hay và chê người ta ngớ ngẫn, mà hãy học thêm và biết chọn lọc tinh hoa của người khác mà ứng dụng vô công việc của mình. Bạn có giỏi thì cứ cắt bằng tay đi rồi nghiền nát, còn tôi thì dùng máy xay sinh tố vậy!
......

Tôi đã nói ở bài #813 là nói về nhận định của bác siwtom, bạn đừng có chen ngang vào nhé
Nhưng bạn đã cố tình viết, thì tôi trả lời:

Không đúng Hoàng Trọng Nghĩa ơi,

Khi chọn một công cụ có sẵn được ví như ta chọn máy sinh tố để xay hoa quả: Không ai bảo chọn máy sinh tố là ngớ ngẩn cả, mà cái khái niệm nghĩ máy sinh tố không có phải cắt chém (lặp đi lặp lại việc cắt chém) thì là sai lầm ngớ ngẩn (ngớ ngẫn ở đây là đãng trí là lơ đãng là có thể chưa hiểu cơ bản, hay có thể dù không biết các công cụ có dùng vòng lặp hay không mà cứ khẳng định như đúng rùi là không có vòng lặp - vì đã đem ra đố thì tự mình phải có giải đáp, đáp án rui - không thể đánh lận còn đen muốn biết không hỏi mà lại ra vẻ đi đố được - chắc bạn không rơi vào trường hợp này)

Còn xưa nay ta vẫn có thể nói là nếu vấn đề nào sử dụng được các công cụ của sẵn trong excel, từ DLL tốt (như các DLL đã được Microsoft cung cấp) thì chắc chắn NHANH HƠN nhiều so với nếu chúng ta dùng cách thông thường viết (vì code VBA là code thuộc hạng chưa dịch - chạy ở tầng thứ cấp) - như việc không bao giờ người ta lại so sánh giữa cái có sẵn (máy xay sinh tố) đó với việc dùng từng bước (dùng dao tự cắt) rõ chưa - việc so sánh đó mới là ngớ ngẩn

Tuy thế, tùy từng quy mô công việc mà chúng ta sử dụng hay KHÔNG sử dụng công cụ có sẵn hay không? sao cho hợp lý ví như có mỗi một quả cherry nhỏ mà ném vào máy xay sinh tố thì thật là không đáng,

Túm lại, việc tôi nói "khái niệm về ngớ ngẩn" là ở chỗ đó chứ không phải giật mình đâu bạn ah,

Về việc đố vui ở đây, thì nhiều người nói rùi đó (cũng là lý do mà bài trên tôi chỉ trả lời và giải thích rõ bài #812 của bác siwtom):

------------------------------

ĐỐ VUI tức là ĐỐ cái gì thật ĐƠN GIẢN nhưng ít ai nghĩ ra (đáp án bất ngờ)
Vậy nên bài này chẳng VUI tí nào

...........
p/s : mà hình như chủ đề là " đố vui VBA " còn mấy cái vụ này không được gọi là "đố vui" roài , anh có thể rời bài ra topic " vui để đố " để không vi phạm nội quy :-=

Bạn còn là MOD (mới nhìn lại màu mới thấy) nữa - càng phải cần tự xét lại mình xem bài viết cách hỏi, cách viết như thế đúng là hợp lý chưa nhé... xin cảm ơn
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn cố tình không hiểu vodoi2x nói gì rồi. Tôi nói cố tình vì tôi biết là bạn hiểu. Ý của vodoi2x chỉ là bạn có thể chặt chém hoa quả nhưng cũng có thể dùng máy xay sinh tố. Nhưng không có nghĩa là dùng máy xay sinh tố thì không có hiện tượng chặt chém. Chưa cần mở xem, chưa cần dùng lần nào mà chỉ đọc tên máy cũng đã biết là "chặt chém" có sẩy ra.
Bạn vodoi2x không nói rằng không nên dùng máy xay sinh tố, cũng không nói rằng dùng máy kém hơn hay bất cứ ý nào khác.

Bạn nói là bạn không phải làm A - hàm ý là người khác phải làm A - thì tôi nói rằng: vì bạn dùng B mà B làm A thay bạn. Người khác làm A chẳng qua là họ tự làm. Bạn nói tiếp là bạn đã ra điều kiện là "không được làm A" cơ mà. Nhưng tôi thường đọc rất kỹ bài của người khác nên tôi biết là bạn không ra điều kiện. Tôi lại chỉ ra. Chả nhẽ bạn mất bình tĩnh vì thế sao?

Cả tôi và vodoi2x không nói gì để bạn có thể viết ra những dòng đỏ đỏ. Bình tĩnh lại đi.

Em HIỂU hết những gì mọi người nói
Ẹc... Ẹc...
Có điều tại đồng chí kia nói hơi quá:
Đây là sai lầm ngớ ngẩn nhất của nhiều người sử dụng - cứ tưởng đó không phải dùng vòng lặp (khi sử dụng công cụ khác)

Vì thế, đôi khi ta cần rèn luyện từ bước cơ bản, và hiểu bản chất của các công cụ chứ không phải nói sai từ như thế dẫn đến nhiều người hiểu lầm
Ngớ ngẩn gì đâu chứ trong khi ta thấy nó KHÔNG VÒNG LẬP thì ta nói nó không lập thôi (bên trong ruốt nó lập hay không thây kệ nó)
Vấn đề là: Nếu ta tự viết được cái của riêng ta nó NHANH hơn thì ta xài, không thì cứ xài cái mà ta nghĩ là KHÔNG LẬP kia cho khỏe
Có gì đâu mà NGỚ với NGẨN nhỉ?
Cũng giống như dùng VBScript.RegEx, ta thấy nó không vòng lập và gọn thì ta xài ---> Ai rảnh đâu mà suy nghĩ bên trong ruột nó viết thế nào. Mà dù có cố suy nghĩ thì ta chắc gì đã biết bên trong nó có LẬP HAY KHÔNG LẬP mà bảo là NÓI SAI TỪ
----------------
Ngộ thiệt (tại ku Nghĩa bực mình thôi chứ em thì chẳng quan tâm)
Ẹc... Ẹc...
 
Upvote 0
Hehehe, hiểu lầm cả, mọi người bỏ qua vấn đề không vui đi, đây là box đố vui mà!

Không biết ai có code nào muốn đố cho vui không nhỉ? Tôi thấy rằng mình học được rất nhiều từ các bài đố này đó.

Thanks.
 
Upvote 0
Em HIỂU hết những gì mọi người nói
Ẹc... Ẹc...
Có điều tại đồng chí kia nói hơi quá:

Ngớ ngẩn gì đâu chứ trong khi ta thấy nó KHÔNG VÒNG LẬP thì ta nói nó không lập thôi (bên trong ruốt nó lập hay không thây kệ nó)
Vấn đề là: Nếu ta tự viết được cái của riêng ta nó NHANH hơn thì ta xài, không thì cứ xài cái mà ta nghĩ là KHÔNG LẬP kia cho khỏe
Có gì đâu mà NGỚ với NGẨN nhỉ?
Cũng giống như dùng VBScript.RegEx, ta thấy nó không vòng lập và gọn thì ta xài ---> Ai rảnh đâu mà suy nghĩ bên trong ruột nó viết thế nào. Mà dù có cố suy nghĩ thì ta chắc gì đã biết bên trong nó có LẬP HAY KHÔNG LẬP mà bảo là NÓI SAI TỪ
----------------
Ngộ thiệt (tại ku Nghĩa bực mình thôi chứ em thì chẳng quan tâm)
Ẹc... Ẹc...


Khẳng định đó là sai từ, để lần sau chúng ta cùng không lặp lại ndu ah,

Vì nếu không lần sau lại đố tiếp lại nói KHÔNG DÙNG VÒNG LẶP thì làm nhiều người hiểu lầm sai bản chất vấn đề- và mất hết đi ý nghĩa thuật toán cơ bản (dù các công cụ kia vẫn sử dụng các thuật toán cơ bản mà thui - chúng ta cũng có thể từ thuật toán cơ bản mà xây dựng các công cụ tương tự chứ không phải cao siêu gì - đây cũng là cách hiểu sai về "đi tắt đón đầu" cuối cùng người ta lại vượt trước chúng ta vì họ đã có cái cơ bản nền tảng đê vượt và ta cứ trên mây trên ngọn)
 
Upvote 0
Khẳng định đó là sai từ, để lần sau chúng ta cùng không lặp lại ndu ah,

Vì nếu không lần sau lại đố tiếp lại nói KHÔNG DÙNG VÒNG LẶP thì làm nhiều người hiểu lầm sai bản chất vấn đề- và mất hết đi ý nghĩa thuật toán cơ bản (dù các công cụ kia vẫn sử dụng các thuật toán cơ bản mà thui - chúng ta cũng có thể từ thuật toán cơ bản mà xây dựng các công cụ tương tự chứ không phải cao siêu gì - đây cũng là cách hiểu sai về "đi tắt đón đầu" cuối cùng người ta lại vượt trước chúng ta vì họ đã có cái cơ bản nền tảng đê vượt và ta cứ trên mây trên ngọn)
Hãy suy nghĩ đơn giản chút đi bạn, theo tui nghĩ thì việc viết không dùng vòng lặp có nghĩa là mình không được viết vòng lặp, nhưng không cấm việc sử dụng những công cụ mà bên trong nó có vòng lặp hay là không. Ta chả cần quan tâm bên trong nó có gì cho mệt xác, chỉ cần biết cái nào hợp, hay cảm thấy hay là dùng.
 
Upvote 0
Khẳng định đó là sai từ, để lần sau chúng ta cùng không lặp lại ndu ah,

Vì nếu không lần sau lại đố tiếp lại nói KHÔNG DÙNG VÒNG LẶP thì làm nhiều người hiểu lầm sai bản chất vấn đề- và mất hết đi ý nghĩa thuật toán cơ bản (dù các công cụ kia vẫn sử dụng các thuật toán cơ bản mà thui - chúng ta cũng có thể từ thuật toán cơ bản mà xây dựng các công cụ tương tự chứ không phải cao siêu gì - đây cũng là cách hiểu sai về "đi tắt đón đầu" cuối cùng người ta lại vượt trước chúng ta vì họ đã có cái cơ bản nền tảng đê vượt và ta cứ trên mây trên ngọn)

Dạ vâng!
Bạn cho đó là SAI TỪ thì cứ thế đi (vì mình không biết thế nào là ĐÚNG cả, mình thấy nó không lập thì nói không lâp)
Đứng trên cương vị là THÀNH VIÊN thì mình cũng chẳng quan tâm mấy vấn đề này (thích cái nào xài cái đó)
Đứng trên cương vị là MOD thì mình thiết nghĩ cần phải nhắn nhủ đôi lời với bạn: Mai này dù có góp ý gì cũng cố lựa lời mà nói, tránh gây mất tình đoàn kết trên diễn đàn... Vì bạn và các thành viên khác trên diễn đàn này cũng chưa có mối quan hệ tốt đến mức có thể nói sao cũng được
Vậy đi nha!
Chúng ta tiếp tục ĐỐ VUI nhé
 
Upvote 0
Đứng trên cương vị là THÀNH VIÊN thì mình cũng chẳng quan tâm mấy vấn đề này (thích cái nào xài cái đó)
Đứng trên cương vị là MOD thì mình thiết nghĩ cần phải nhắn nhủ đôi lời với bạn: Mai này dù có góp ý gì cũng cố lựa lời mà nói, tránh gây mất tình đoàn kết trên diễn đàn... Vì bạn và các thành viên khác trên diễn đàn này cũng chưa có mối quan hệ tốt đến mức có thể nói sao cũng được

Chính vì dùng gì thì dùng --> thì mới cần đừng áp đặt quan niệm SAI của mình cho người khác,

Không phải không có lựa lời, mà đó là bài nói về khái niệm sai lầm (như là chắc chắn KHÔNG CÓ VÒNG LẶP trong các công cụ có sẵn) đó cần bỏ (nhấn mạnh để bỏ) --> không nói đến ai cả, thì sao là "mất tình đoàn kết" - trong chuyên môn cần thẳng thắn thừa nhận (khái niệm không đúng thì phải nói là không đúng), đừng tự ti như vậy

Cám ơn ndu đã nói vậy, và có thể hiểu là có quá nhiều nhạy cảm ở đây chăng (?)

Ở đây tôi thấy cách của huuthang_bd (selection sort) hay Quick sort của hungpecc1 (dĩ nhiên còn nhiều thuật toán sắp xếp khác - đó mới điều cần học cần nói mà không bị phủ nhận hoặc mờ đi bởi nhận định sai) là các cách cơ bản và ứng dụng tốt trong bài này - vì chẳng bao giờ có chuỗi nào tách mà dài lê văn thê đến hàng 10 000 thành phần tức là vài chục ngàn ký tự cả (nếu thế thì gọi là phi thực tế)

Chúc các bạn tiếp tục duy trì chủ đề đúng ý nghĩa đố vui của nó
 
Lần chỉnh sửa cuối:
Upvote 0
Xét về tốc độ, thì 2 thằng em này cũng ngang ngang nhau, nếu dùng For ... Next do mình xử lý chuỗi thì có mà chờ dài cổ, tôi đã thử code của huuthang_bd với 1,000 mục cho ra thời gian đâu có bao nhiêu: 114 giây! Trong khi đó, với 60,000 mục thì 2 thằng em trên xử lý trong vòng 2 giây.

Tôi thấy so sánh như thế là không ... , thôi cứ gọi là "không công bằng".

Bạn đố về việc sắp xếp nhưng không phải đố về code sắp xếp tốc độ nhanh mà là code sắp xếp để không ra 1,4,5,6,7,10 mà ra 1,4-7,10.

Như vậy người làm sẽ viết code chỉ để làm ra kết quả. Họ có thể chỉ viết code đơn giản (ngại?) mà không đặt trọng tâm vào việc viết code dùng để sort (không là nội dung của bài đố). Vì tôi tin rằng huuthang_bd biết nhiều kiểu sort chứ không phải kiểu đơn giản nhưng rất chậm như bạn dùng để so sánh.

Đã có lúc tôi đã gửi lên GPE code dùng để sort theo thuật toán quick sort.

http://www.giaiphapexcel.com/forum/...cho-sắp-xếp-mảng-nhờ-test-hộ-và-góp-ý

Cũng cần trả lời ndu về ý kiến

Trên diễn đàn mọi người vẫn mong có được 1 công cụ sắp xếp tiếng Việt hơn anh à!

Tất nhiên tôi cũng có

Mã:
Function Sort2DArray(ByVal Arr, ArrIndex, _
    col1 As Long, Optional ByVal sortAtoZ1 As Boolean = True, Optional ByVal convert1 As convert_col = cc_nothing, Optional ByVal phan_biet_hoa_thuong1 As Boolean = True, _
    Optional ByVal col2 As Long = -32768, Optional ByVal sortAtoZ2 As Boolean = True, Optional ByVal convert2 As convert_col = cc_nothing, Optional ByVal phan_biet_hoa_thuong2 As Boolean = True, _
    Optional ByVal col3 As Long = -32768, Optional ByVal sortAtoZ3 As Boolean = True, Optional ByVal convert3 As convert_col = cc_nothing, Optional ByVal phan_biet_hoa_thuong3 As Boolean = True)

Mà khi cần sort cột có tiếng Việt thì thiết lập thông số convert. Tất nhiên lúc đó code sẽ làm lâu hơn chút vì phải mã hóa các chuỗi.

QuickSort1DArray được sinh ra để sort mảng số hoặc chuỗi không chứa ký tự Việt. Vì có những tình huống như thế mà chả nhẽ giết gà lại dùng dao mổ trâu? Mà dùng dao mổ trâu dứt khoát chậm hơn. Cầm một con dao nhỏ thao tác vẫn tiện hơn cầm một con dao lớn.
QuickSort1DArray dứt khoát nhanh hơn vả lại nó chỉ dùng cho mảng 1 chiều.
--------------

Vì hàm của tôi viết cho dữ liệu đầu vào là mảng - tên là QuickSort1DArray mà - mà của các bạn là String nhưng tôi không muốn sửa vậy thì tôi chịu "thiệt thòi", tức tách từ chuỗi vào mảng sau đó khi có kết quả thì lại nối thành chuỗi.

Do máy tôi rất yếu nên tôi ngại test với dữ liệu lớn. Vậy các bạn test hộ code sau và thông báo nhé

À, giải thích thêm. Tại sao tôi không gọi
Mã:
QuickSort1DArray tmp, LBound(tmp), UBound(tmp), True

mà lại tạo Arr từ tmp rồi gọi

Mã:
QuickSort1DArray Arr, LBound(Arr), UBound(Arr), True

???

Bởi hàm của tôi sort cả mảng số lẫn mảng chuỗi. Mà vd.
3, 4, 5, 7, 8, 9 < 20
nhưng
"20" < "3", "4", "5", "7", "8", "9"

Các bạn dùng chuỗi nhưng các bạn lại lại "bắt" 3 < 20, tức coi 3 và 20 như số nên bắt buộc tôi phải sort mảng số. Vì tmp là mảng chuỗi nên tôi phải tạo mảng số Arr

Module1
Mã:
Private Declare Function GetTickCount Lib "kernel32.dll" () As Long

Function SortArrayScript(SerStr As String) As String
    SerStr = "('" & SerStr & "').split(',').sort(function(a,b){return (a-b)}).join(',')" ' & ".reverse()" 'if DESC
    With CreateObject("MSScriptControl.ScriptControl")
        .Language = "JavaScript"
        SortArrayScript = .Eval(SerStr)
    End With
End Function

Function SortArraySystem(SerStr As String) As String
    Dim str As String, Arr, i As Long
    Arr = Split(SerStr, ",")
    With CreateObject("System.Collections.ArrayList")
        For i = 0 To UBound(Arr)
            .Add CLng(Arr(i))
        Next
        .Sort: Arr = .ToArray
    End With
    SortArraySystem = Join(Arr, "-")
End Function

Public Sub QuickSort1DArray(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
'    Arr laĚ maŇng câĚn săěp xęěp
'    sortAtoZ xaěc điňnh caěch săěp xęěp tăng hay giaŇm
'    iLo laĚ câňn dýőěi cuŇa maŇng Arr, iHi laĚ câňn tręn cuŇa maŇng Arr
Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s

    Do
        Lo = iLo
        Hi = iHi
        
        iMid = Arr((Lo + Hi) \ 2)
        Do
            If sortAtoZ Then
                Do While Arr(Lo) < iMid
                    Lo = Lo + 1
                Loop
                Do While Arr(Hi) > iMid
                    Hi = Hi - 1
                Loop
            Else
                Do While Arr(Lo) > iMid
                    Lo = Lo + 1
                Loop
                Do While Arr(Hi) < iMid
                    Hi = Hi - 1
                Loop
            End If
            
            If Lo <= Hi Then
                If sortAtoZ Then
                    DoChange = (Arr(Lo) > Arr(Hi))
                Else
                    DoChange = (Arr(Lo) < Arr(Hi))
                End If
                If DoChange Then
                    s = Arr(Lo)
                    Arr(Lo) = Arr(Hi)
                    Arr(Hi) = s
                End If
                
                Lo = Lo + 1
                Hi = Hi - 1
            End If
        Loop Until Lo > Hi
        If Hi > iLo Then QuickSort1DArray Arr, iLo, Hi, sortAtoZ
        iLo = Lo
    Loop Until Lo >= iHi
End Sub

Sub test()
Dim s As String, a As String, t As Double, k As Long, Arr() As Long, tmp, n As Long
    
    t = GetTickCount
    For k = 1 To 60000
        a = SortArrayScript("1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15,14,10,7,20")
    Next k
    Debug.Print "SortArrayScript:: " & (GetTickCount - t) / 1000 & " " & a

    t = GetTickCount
    For k = 1 To 60000
        a = SortArraySystem("1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15,14,10,7,20")
    Next k
    Debug.Print "SortArraySystem: " & (GetTickCount - t) / 1000 & " " & a
    
    t = GetTickCount
    For k = 1 To 60000
        a = ""
        tmp = Split("1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15,14,10,7,20", ",")
        ReDim Arr(LBound(tmp) To UBound(tmp))
        For n = LBound(tmp) To UBound(tmp)
            Arr(n) = tmp(n)
        Next n
        
        QuickSort1DArray Arr, LBound(Arr), UBound(Arr), True
        
        For n = LBound(tmp) To UBound(tmp)
            a = a & Arr(n) & "-"
        Next n
        a = Left(a, Len(a) - 1)
    Next k
    Debug.Print "QuickSort1DArray: " & (GetTickCount - t) / 1000 & " " & a
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Hãy suy nghĩ đơn giản chút đi bạn, theo tui nghĩ thì việc viết không dùng vòng lặp có nghĩa là mình không được viết vòng lặp, nhưng không cấm việc sử dụng những công cụ mà bên trong nó có vòng lặp hay là không. Ta chả cần quan tâm bên trong nó có gì cho mệt xác, chỉ cần biết cái nào hợp, hay cảm thấy hay là dùng.

Chẳng qua là giải thích cho rõ vòng lặp nó nằm ở đâu thôi. Nhưng ...

Nếu nói về bài cụ thể này thì tôi có cảm giác là những chỗ đỏ đỏ gợi ý là: "Tôi cấm không được dùng vòng lặp "trực tiếp" (tức "gián tiếp thì được) vậy khi tôi không dùng vòng lặp "trực tiếp" thì tôi khoe"

Nếu tôi cảm giác đúng thì bạn hãy chỉ ra cho tôi trong tất cả các bài viết của Nghĩa chỗ nào nói cấm dùng vòng lặp?
 
Upvote 0
Hãy suy nghĩ đơn giản chút đi bạn, theo tui nghĩ thì việc viết không dùng vòng lặp có nghĩa là mình không được viết vòng lặp, nhưng không cấm việc sử dụng những công cụ mà bên trong nó có vòng lặp hay là không. Ta chả cần quan tâm bên trong nó có gì cho mệt xác, chỉ cần biết cái nào hợp, hay cảm thấy hay là dùng.

Chính suy nghĩ đơn giản đó mới dẫn đến hiểu nhầm, đến sai lầm bạn ah,

Phải chuẩn về mặt ngữ nghĩa khi nói về chuyên môn - nhất là lại đem đố (thành đề cho người khác) - tôi không nói bài riêng HTN đang đố mà nói chung về khái niệm sai lầm đó -- dẫn đến sự lầm tưởng cho người đọc, người áp dụng

Bạn hay ai thích đơn giản thì giữ riêng cho mình đừng viết ra khuyên người khác hay thách đố điều (đơn giản) sai đó được (dĩ nhiên có thể nói/ viết ra thì phải mở ngoặc giải thích rõ ràng - mà đã thế thì thà theo chuẩn chung phải hay hơn không). Vì đây là diễn đàn công khai cho cộng đồng, thì chúng ta phải chọn cái chuẩn chung cái đúng chung. Có như vậy mới giúp mọi người cùng tiến chứ không phải cứ hiểu ngầm định hay giả định quan niệm riêng của tôi.
 
Upvote 0
Module1
Mã:
Private Declare Function GetTickCount Lib "kernel32.dll" () As Long

vì chẳng bao giờ có chuỗi nào tách mà dài lê văn thê đến hàng 10 000 thành phần tức là vài chục ngàn ký tự cả (nếu thế thì gọi là phi thực tế)

Đọc bài #832 của bạn vodoi2x tôi giật mình: có thể Nghĩa đã nhập một chuỗi dài lê thê và sắp xếp 1 lần chứ không phải test 60000 lần một chuỗi ngắn.

Vậy thì ta test 1 lần với dữ liệu lớn. Nhưng như thế thì tôi thiệt thòi quá. Việc tách chuỗi vào mảng rồi từ kết quả nối chuỗi có "-" mất nhiều thời gian quá.

Ta thử cho đk là như nhau và xét thử với đk:

1. Chỉ đo thời gian cho việc sắp xếp thôi. Tức đo thời gian mà QuickSort1DArray và "System.Collections.ArrayList" đã dùng. Vì chuyện nối chuỗi bằng "-" hay "," là nhu cầu của bài toán cụ thể chứ không phải là chuyện của hàm Sort là hàm universal chỉ làm việc sort thôi.

2. Dữ liệu vào là mảng Long. Đã thử tốc độ thì làm luôn với mảng có nửa triệu số

3. Dữ liệu ra là mảng đã sắp xếp

4. Tôi sửa SortArraySystem để dữ liệu vào là mảng

Mã:
Private Declare Function GetTickCount Lib "kernel32.dll" () As Long

Function SortArraySystem(Arr)
    Dim i As Long
    With CreateObject("System.Collections.ArrayList")
        For i = LBound(Arr) To UBound(Arr)
            .Add Arr(i)
        Next
        .Sort
        SortArraySystem = .ToArray
    End With
End Function

Public Sub QuickSort1DArray(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s

    Do
        Lo = iLo
        Hi = iHi
        
        iMid = Arr((Lo + Hi) \ 2)
        Do
            If sortAtoZ Then
                Do While Arr(Lo) < iMid
                    Lo = Lo + 1
                Loop
                Do While Arr(Hi) > iMid
                    Hi = Hi - 1
                Loop
            Else
                Do While Arr(Lo) > iMid
                    Lo = Lo + 1
                Loop
                Do While Arr(Hi) < iMid
                    Hi = Hi - 1
                Loop
            End If
            
            If Lo <= Hi Then
                If sortAtoZ Then
                    DoChange = (Arr(Lo) > Arr(Hi))
                Else
                    DoChange = (Arr(Lo) < Arr(Hi))
                End If
                If DoChange Then
                    s = Arr(Lo)
                    Arr(Lo) = Arr(Hi)
                    Arr(Hi) = s
                End If
                
                Lo = Lo + 1
                Hi = Hi - 1
            End If
        Loop Until Lo > Hi
        If Hi > iLo Then QuickSort1DArray Arr, iLo, Hi, sortAtoZ
        iLo = Lo
    Loop Until Lo >= iHi
End Sub

Function Draw(Arr, Amount As Long)
Dim index As Long, k As Long, d As Long, c As Long, tmpArr, original

    If Amount > UBound(Arr) - LBound(Arr) + 1 Then Exit Function
    original = Arr
    
    ReDim tmpArr(1 To Amount)
    d = LBound(original)
    c = UBound(original)
    Randomize
    For k = 1 To Amount
        index = Int(Rnd() * (c - d + 1)) + d
        tmpArr(k) = original(index)
        original(index) = original(k + LBound(original) - 1)
        d = d + 1
    Next k
    Draw = tmpArr
End Function

Sub test()
Dim t As Double, k As Long, Arr, tmp, identic As Boolean, he
    ReDim Arr(1 To 500000)
    ReDim he(1 To 500000)
    
    For k = 1 To 500000
        Arr(k) = k
    Next k
    Arr = Draw(Arr, 500000)
    
    For k = 1 To 500000
        he(k) = Arr(k)
    Next k
'    ------------------------------------------------------------------    
    t = GetTickCount
    tmp = SortArraySystem(Arr)
    Debug.Print "SortArraySystem: " & (GetTickCount - t) / 1000
    
    t = GetTickCount
    QuickSort1DArray he, LBound(he), UBound(he), True
    Debug.Print "QuickSort1DArray: " & (GetTickCount - t) / 1000
    
'    kiem tra xem 2 mang tmp va Arr co nhu nhau khong
    identic = True
    For k = 1 To 500000
        If tmp(k - 1) <> he(k) Then
            identic = False
            Exit For
        End If
    Next k
    
    Debug.Print "identic = " & identic
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
2. Dữ liệu vào là mảng Long. Đã thử tốc độ thì làm luôn với mảng có nửa triệu số

3. Dữ liệu ra là mảng đã sắp xếp

4. Tôi sửa SortArraySystem để dữ liệu vào là mảng
kết quả em test là như sau :
[INFO1]
SortArraySystem: 16.469 (1)
QuickSort1DArray: 7.453
identic = True[/INFO1]
Em nghĩ SortArraySystem sở dĩ lâu hơn vì nó phải mất công thực hiện 2 công việc :
*1 khai báo trễ createObject
* Tốn 1 vòng for để lại đưa từng phần tử mảng vào ArrayList ( .Add Arr(i))
--> em test lại như sau :
[GPECODE=vb]
Function SortArraySystem(Arr)
Dim i As Long
With CreateObject("System.Collections.ArrayList")
For i = LBound(Arr) To UBound(Arr)
.Add Arr(i)
Next
'.Sort
SortArraySystem = .ToArray
End With
End Function
[/GPECODE]
[GPECODE=vb]
Sub ktr()
Dim t As Double, k As Long, Arr
ReDim Arr(1 To 500000)
For k = 1 To 500000
Arr(k) = k
Next k
Arr = Draw(Arr, 500000)
t = GetTickCount
tmp = SortArraySystem(Arr)
Debug.Print "SortArraySystem: " & (GetTickCount - t) / 1000
End Sub
[/GPECODE]
kết quả là :SortArraySystem: 13.781 (2)

Tức là theo em phương thức .sort của System.Collections.ArrayList sẽ là =(1)-(2) =16.469-13.781=2.6(s) --> tốc độ quá khủng chăng !$@!!

theo em hiểu thì cách sắp xếp của anh là phân đoạn
Mã:
iMid = Arr((Lo + Hi) \ 2)

-trường hợp xấu nhất là :iMid sẽ là giá trị lớn nhất , hoặc nhỏ nhất trong đoạn chia từ Lo đến Hi
- Nếu đẹp nhất là IMid bằng giá trị trung bình trong đoạn Lo Hi

---> em thử sửa iMid = INT[Rnd(Hi-Li+1)+Li] thì có lúc nhanh lúc chậm ,(có lúc chỉ còn 6,2 s < QuickSort1DArray =7.453)--> có cách nào chọn Imid tối ưu nhất không anh !

Thanks anh !
 
Lần chỉnh sửa cuối:
Upvote 0
kết quả em test là như sau :
[INFO1]
SortArraySystem: 16.469 (1)
QuickSort1DArray: 7.453
identic = True[/INFO1]

Trên máy cũ kỹ của tôi kết quả hơi khác, thường là SortArraySystem/QuickSort1DArray ≈ 7

theo em hiểu thì cách sắp xếp của anh là phân đoạn
Mã:
iMid = Arr((Lo + Hi) \ 2)

-trường hợp xấu nhất là :iMid sẽ là giá trị lớn nhất , hoặc nhỏ nhất trong đoạn chia từ Lo đến Hi
- Nếu đẹp nhất là IMid bằng giá trị trung bình trong đoạn Lo Hi

---> em thử sửa iMid = INT[Rnd(Hi-Li+1)+Li] thì có lúc nhanh lúc chậm ,(có lúc chỉ còn 6,2 s < QuickSort1DArray =7.453)--> có cách nào chọn Imid tối ưu nhất không anh !

Quick sort nó là thế.
Nếu bạn định xét iMid với kiểu chọn tối ưu thì xin mời tự nghĩ ra thuật toán mới nhé.
Không có kiểu sort nào hoàn hảo 100%, trong mọi trường hợp cả. Bởi nếu thế thì có "ngần ấy" cách sort để mà làm gì? Chỉ có kiểu A tới ưu hơn B mà thôi.

À, bạn hãy chạy thử thêm code sau - sort tăng dần một mảng đã được sắp xếp giảm dần

Kết quả của tôi là

Mã:
SortArraySystem: 60,417
QuickSort1DArray: 4,947
identic = True

SortArraySystem: 62,48
QuickSort1DArray: 5,719
identic = True

SortArraySystem: 63,681
QuickSort1DArray: 4,547
identic = True

Code dùng cho test

Mã:
Sub test()
Dim t As Double, k As Long, Arr, tmp, identic As Boolean, he
    ReDim Arr(1 To 500000)
    ReDim he(1 To 500000)
    
    For k = 1 To 500000
        Arr(k) = 500001 - k
    Next k
    
    For k = 1 To 500000
        he(k) = Arr(k)
    Next k
'    ------------------------------------------------------------------
    t = GetTickCount
    tmp = SortArraySystem(Arr)
    Debug.Print "SortArraySystem: " & (GetTickCount - t) / 1000
    
    t = GetTickCount
    QuickSort1DArray he, LBound(he), UBound(he), True
    Debug.Print "QuickSort1DArray: " & (GetTickCount - t) / 1000
    
'    kiem tra xem 2 mang tmp va Arr co nhu nhau khong
    identic = True
    For k = 1 To 500000
        If tmp(k - 1) <> he(k) Then
            identic = False
            Exit For
        End If
    Next k
    
    Debug.Print "identic = " & identic
End Sub

Và nếu muốn thì cả sort tăng dần một mảng đã được sắp xếp tăng dần

Tức thay

Mã:
For k = 1 To 500000
        Arr(k) = [B][COLOR=#ff0000]500001 -[/COLOR][/B] k
    Next k
    
    For k = 1 To 500000
        he(k) = Arr(k)
    Next k

bằng

Mã:
For k = 1 To 500000
        Arr(k) = k
    Next k
    
    For k = 1 To 500000
        he(k) = Arr(k)
    Next k
 
Lần chỉnh sửa cuối:
Upvote 0
Trên máy cũ kỹ của tôi kết quả hơi khác, thường là SortArraySystem/QuickSort1DArray ≈ 7



Quick sort nó là thế.
Nếu bạn định xét iMid với kiểu chọn tối ưu thì xin mời tự nghĩ ra thuật toán mới nhé.
Không có kiểu sort nào hoàn hảo 100%, trong mọi trường hợp cả. Bởi nếu thế thì có "ngần ấy" cách sort để mà làm gì? Chỉ có kiểu A tới ưu hơn B mà thôi.

À, bạn hãy chạy thử thêm code sau - sort tăng dần một mảng đã được sắp xếp giảm dần

Kết quả của tôi là

Mã:
SortArraySystem: 60,417
QuickSort1DArray: 4,947
identic = True

SortArraySystem: 62,48
QuickSort1DArray: 5,719
identic = True

SortArraySystem: 63,681
QuickSort1DArray: 4,547
identic = True

Code dùng cho test

Mã:
Sub test()
Dim t As Double, k As Long, Arr, tmp, identic As Boolean, he
    ReDim Arr(1 To 500000)
    ReDim he(1 To 500000)
    
    For k = 1 To 500000
        Arr(k) = 500001 - k
    Next k
    
    For k = 1 To 500000
        he(k) = Arr(k)
    Next k
'    ------------------------------------------------------------------
    t = GetTickCount
    tmp = SortArraySystem(Arr)
    Debug.Print "SortArraySystem: " & (GetTickCount - t) / 1000
    
    t = GetTickCount
    QuickSort1DArray he, LBound(he), UBound(he), True
    Debug.Print "QuickSort1DArray: " & (GetTickCount - t) / 1000
    
'    kiem tra xem 2 mang tmp va Arr co nhu nhau khong
    identic = True
    For k = 1 To 500000
        If tmp(k - 1) <> he(k) Then
            identic = False
            Exit For
        End If
    Next k
    
    Debug.Print "identic = " & identic
End Sub

Và nếu muốn thì cả sort tăng dần một mảng đã được sắp xếp tăng dần

Tức thay

Mã:
For k = 1 To 500000
        Arr(k) = [B][COLOR=#ff0000]500001 -[/COLOR][/B] k
    Next k
    
    For k = 1 To 500000
        he(k) = Arr(k)
    Next k

bằng

Mã:
For k = 1 To 500000
        Arr(k) = k
    Next k
    
    For k = 1 To 500000
        he(k) = Arr(k)
    Next k

Sau khi test xong, tốc độ thật đáng nể!

Mục đích của em là SORT, tìm những thủ tục, những hàm tối ưu, dự kiến sau này sẽ phát triển sắp xếp dữ liệu trên Excel 2007 trở về sau (hơn 1 triệu hàng), vì thế mới tung chiêu đố.

Tuy nhiên, em vẫn đánh giá cao SortArraySystem vì nó Sort vừa chuỗi vừa số được, chẳng hạn sắp xếp từ chuỗi này:

str = "a,9,8,c,6,7,b,3,a,f,4,6,7,e,10,1,11,33"

Kết quả = 1,10,11,3,33,4,6,6,7,7,8,9,a,a,b,c,e,f

Không biết hàm mình viết có được vậy không!? Hay có thể là hay hơn (sắp xếp chỗ tô đậm cho đúng vị trí)?

'---------------------------------------------------------

Hỏi xong mới được đọc bài này:

Hàm dùng cho sắp xếp mảng - nhờ test hộ và góp ý


Giờ mới thấy bài đó, lẽ ra phải thấy sớm hơn thì khỏi phải đố điếc chi cho mệt nhỉ? Cám ơn Thầy siwtom nhé!
 
Lần chỉnh sửa cuối:
Upvote 0
Tuy nhiên, em vẫn đánh giá cao SortArraySystem vì nó Sort vừa chuỗi vừa số được, chẳng hạn sắp xếp từ chuỗi này:

str = "a,9,8,c,6,7,b,3,a,f,4,6,7,e,10,1,11,33"

Không phải là "Sort vừa chuỗi vừa số được"

Hàm
Mã:
Function SortArraySystem(SerStr As String) As String
    Dim str As String, Arr, i As Long
    Arr = Split(SerStr, ",")
    With CreateObject("System.Collections.ArrayList")
        For i = 0 To UBound(Arr)
            .Add CLng(Arr(i))
        Next
        .Sort: Arr = .ToArray
    End With
    SortArraySystem = Join(Arr, "-")
End Function

là sắp xếp mảng CHUỖI.
Do Arr được cắt từ chuỗi - Arr = Split(SerStr, ",") - nên nó là mảng chuỗi - mỗi phần tử là chuỗi. Tức vd. ta có "11" chứ không phải 11.

Nhưng trong code
Mã:
Function SortArraySystem(Arr)
    Dim i As Long
    With CreateObject("System.Collections.ArrayList")
        For i = LBound(Arr) To UBound(Arr)
            .Add Arr(i)
        Next
        .Sort
        SortArraySystem = .ToArray
    End With
End Function

Sub test()
Dim k As Long, Arr, tmp
    ReDim Arr(1 To 500000)
    
    For k = 1 To 500000
        Arr(k) = k
    Next k
    Arr = Draw(Arr, 500000)
    tmp = SortArraySystem(Arr)
End Sub

thì ta đã truyền vào hàm SortArraySystem một mảng số. Vì kiểu của mỗi phần tử là số (do Arr(k) = k mà k là Long)
Kết quả = 1,10,11,3,33,4,6,6,7,7,8,9,a,a,b,c,e,f

Không biết hàm mình viết có được vậy không!?
Thì hàm QuickSort1DArray chứ còn hàm nào? Chỉ có điều dữ liệu vào là mảng CHUỖI.

Nhìn thứ tự các số thì hiểu tại sao tôi lại viết trong bài #833
À, giải thích thêm. Tại sao tôi không gọi
Mã:
QuickSort1DArray tmp, LBound(tmp), UBound(tmp), True

mà lại tạo Arr từ tmp rồi gọi

Mã:
QuickSort1DArray Arr, LBound(Arr), UBound(Arr), True
???

Bởi hàm của tôi sort cả mảng số lẫn mảng chuỗi. Mà vd.
3, 4, 5, 7, 8, 9 < 20
nhưng
"20" < "3", "4", "5", "7", "8", "9"

Các bạn dùng chuỗi nhưng các bạn lại lại "bắt" 3 < 20, tức coi 3 và 20 như số nên bắt buộc tôi phải sort mảng số. Vì tmp là mảng chuỗi nên tôi phải tạo mảng số Arr

Bạn nào không hiểu tại sao lại có thứ tự 11, 3, 33, 4 thì tìm hiểu về cách so sánh chuỗi nhé.

Mã:
Sub test()
Dim Arr, s As String
    s = "a,9,8,c,6,7,b,3,a,f,4,6,7,e,10,1,11,33"
    Arr = Split(s, ",")
    
    QuickSort1DArray Arr, LBound(Arr), UBound(Arr), True
    s = Join(Arr, ",")
    Debug.Print s
End Sub

Giờ mới thấy bài đó

Thế là thấm thoát hơn 10 tháng đã trôi qua ...
 
Upvote 0
kết quả em test là như sau :
[INFO1]
SortArraySystem: 16.469 (1)
QuickSort1DArray: 7.453
identic = True[/INFO1]
Em nghĩ SortArraySystem sở dĩ lâu hơn vì nó phải mất công thực hiện 2 công việc :
*1 khai báo trễ createObject
* Tốn 1 vòng for để lại đưa từng phần tử mảng vào ArrayList ( .Add Arr(i))

Tôi không nghĩ vậy!
Cái mình viết chỉ CHUYÊN DÙNG ĐỂ SORT (đâu có làm gì khác hơn)
Thằng System.Collections.ArrayList là 1 công cụ đồ sộ, nó đâu chỉ có SORT
Vậy nên nếu phần sort cho tốc độ thấp hơn cũng là chuyện quá bình thường
Từ xưa tôi vẫn biết cái QuickSort của anh siwtom nó nhanh nhưng phải nói thằng thế này:
- Rất nhiều người lúng túng khi dùng QụickSort của anh siwtom (em nói thật, mong anh đừng buồn). Có thể vì cách viết của anh chưa "gần gũi" chẳng?
- Với System.Collections.ArrayList: Đơn giản + tốc độ chấp nhận được + Nhìn là hiểu + áp dụng được ngay
 
Upvote 0
Tôi không nghĩ vậy!
Cái mình viết chỉ CHUYÊN DÙNG ĐỂ SORT (đâu có làm gì khác hơn)
Thằng System.Collections.ArrayList là 1 công cụ đồ sộ, nó đâu chỉ có SORT
Vậy nên nếu phần sort cho tốc độ thấp hơn cũng là chuyện quá bình thường
Từ xưa tôi vẫn biết cái QuickSort của anh siwtom nó nhanh nhưng phải nói thằng thế này:
- Rất nhiều người lúng túng khi dùng QụickSort của anh siwtom (em nói thật, mong anh đừng buồn). Có thể vì cách viết của anh chưa "gần gũi" chẳng?
- Với System.Collections.ArrayList: Đơn giản + tốc độ chấp nhận được + Nhìn là hiểu + áp dụng được ngay

Nếu chỉ nói về dùng thì hàm chỉ vỏn vện có 4 đối số. Ý nghĩa của chúng thế nào thì tôi có giải thích. Vậy lúng túng khi dùng là thế nào?

Bạn có thể nói rõ hơn cái "gần gũi" không? Nếu nói code sai, code viết chưa tối ưu ... thì đều có thể tranh luận được. Vì code thế nào thì ai cũng nhìn thấy. Còn nói chưa "gần gũi" thì chịu rồi. Chưa gần gũi là cảm nhân chủ quan, là cái có muôn vàn bộ mặt. Cái với anh A là gần gũi có thể với anh B là không gần gũi.
Với cái chưa "gần gũi" đó thì bó tay rồi.
 
Upvote 0
Nếu chỉ nói về dùng thì hàm chỉ vỏn vện có 4 đối số. Ý nghĩa của chúng thế nào thì tôi có giải thích. Vậy lúng túng khi dùng là thế nào?

Bạn có thể nói rõ hơn cái "gần gũi" không? Nếu nói code sai, code viết chưa tối ưu ... thì đều có thể tranh luận được. Vì code thế nào thì ai cũng nhìn thấy. Còn nói chưa "gần gũi" thì chịu rồi. Chưa gần gũi là cảm nhân chủ quan, là cái có muôn vàn bộ mặt. Cái với anh A là gần gũi có thể với anh B là không gần gũi.
Với cái chưa "gần gũi" đó thì bó tay rồi.

Đây anh
Mã:
Public Sub QuickSort1DArray(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
Em vẫn chưa hiểu biến iLo, iHi để làm gì?
Đứng trên cương vị người dùng thì em chỉ cần thế này:
Mã:
Public Sub QuickSort1DArray(arr, ByVal sortAtoZ As Boolean)
Tức sort mảng nào, và sort tăng dần hay giảm dần
Vậy thôi em nghĩ là đủ rồi
(Hay không còn có ý gì khác về 2 biến trên)
 
Upvote 0
Đây anh
Mã:
Public Sub QuickSort1DArray(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
Em vẫn chưa hiểu biến iLo, iHi để làm gì?
Đứng trên cương vị người dùng thì em chỉ cần thế này:
Mã:
Public Sub QuickSort1DArray(arr, ByVal sortAtoZ As Boolean)
Tức sort mảng nào, và sort tăng dần hay giảm dần
Vậy thôi em nghĩ là đủ rồi
(Hay không còn có ý gì khác về 2 biến trên)

Em thì hiểu như vậy , không biết có đúng không :
iLo = integer Low, iHi = integer Hight --> tức là chỉ số trên và dưới của một đoạn phần tử trong mảng : Arr(iLo) : Arr(iHi)
* Vì đây là cách viết theo thuật toán đệ quy --> bắt buộc phải có 2 đối số iLo và iHi trong QuickSort
 
Upvote 0
Em thì hiểu như vậy , không biết có đúng không :
iLo = integer Low, iHi = integer Hight --> tức là chỉ số trên và dưới của một đoạn phần tử trong mảng : Arr(iLo) : Arr(iHi)
* Vì đây là cách viết theo thuật toán đệ quy --> bắt buộc phải có 2 đối số iLo và iHi trong QuickSort

Không biết bạn nói có đúng không... nhưng nếu đúng là vậy thì rõ ràng 2 biến này gây lúng túng cho người dùng ---> Rõ ràng tôi không cần nó để làm gì
 
Upvote 0
Em thì hiểu như vậy , không biết có đúng không :
iLo = integer Low, iHi = integer Hight --> tức là chỉ số trên và dưới của một đoạn phần tử trong mảng : Arr(iLo) : Arr(iHi)
* Vì đây là cách viết theo thuật toán đệ quy --> bắt buộc phải có 2 đối số iLo và iHi trong QuickSort

Hình như tôi cũng đã thấy 2 biến đó nó thừa thừa sao đó, nên đã viết ở bài này:

http://www.giaiphapexcel.com/forum/...nhờ-test-hộ-và-góp-ý&p=521349#post521349

Có thể về nguyên tắc của thuật toán nào đó thì phải bắt buộc như thế, nhưng với VBA của Excel thì không cần, vậy thì ta cứ giản thiểu biến một cách không cần thiết là được chứ nhỉ?
 
Upvote 0
Hình như tôi cũng đã thấy 2 biến đó nó thừa thừa sao đó, nên đã viết ở bài này:

http://www.giaiphapexcel.com/forum/...nhờ-test-hộ-và-góp-ý&p=521349#post521349

Có thể về nguyên tắc của thuật toán nào đó thì phải bắt buộc như thế, nhưng với VBA của Excel thì không cần, vậy thì ta cứ giản thiểu biến một cách không cần thiết là được chứ nhỉ?
Em không hiểu ý anh lắm, em lấy 1 ví dụ ngắn gọn thế này !
[GPECODE=vb]
Sub quicksort(subArr(), ByVal L As Long, ByVal U As Long)
Dim i As Long, j As Long
Dim pivot, TG
If L >= U Then Exit Sub <--- Đây là điểm neo, nếu không có điểm này sẽ là vòng lặp vô tận
i = L: j = U
pivot = Int(Rnd() * (j - i + 1) + i)
Do
While subArr(i) < subArr(pivot)
i = i + 1
Wend
While subArr(j) > subArr(pivot)
j = j - 1
Wend
If i <= j Then
TG = subArr(i): subArr(i) = subArr(j): subArr(j) = TG
i = i + 1
j = j - 1
End If
Loop Until i > j
quicksort subArr, L, j <---------- Đệ quy với tham số L,J
quicksort subArr, i, U<---------- Đệ quy với tham số i,U
End Sub
Nếu mà không có 2 tham số L,U thì anh phải tạo thêm 1 điểm neo nữa
[/GPECODE]
Tài liệu tham khảo trên google :
1. Sơ lược
Giải thuật Quick Sort là một phương pháp sắp xếp theo kiểu phân đoạn được cải tiến từ thuật toán Selection Sort do C.A.R Hoare đưa ra. Cụ thể như sau:

Đầu tiên cần chọn một phần tử nào đó của dãy làm chốt hay phần tử quay (pivot).
Trong bước tiếp theo, các phần tử nhỏ hơn chốt phải được xếp vào phía trước chốt (đầu dãy) và các
phần tử lớn hơn được xếp vào phía sau chốt (cuối dãy). Để có được sự phân loại này, các phần tử sẽ được so
sánh với chốt và hoán đổi vị trí cho nhau hoặc cho chốt nếu nó lớn hơn chốt mà lại nằm trước
hoặc nhỏ hơn chốt mà lại nằm sau. Khi lượt hoán đổi đầu tiên thực hiện xong thì dãy được chia
thành 2 đoạn: 1 đoạn bao gồm các phần tử nhỏ hơn chốt, đoạn còn lại bao gồm các phần tử lớn
hơn chốt, còn chốt chính là phần tử đã được sắp xếp.
Áp dụng kĩ thuật trên cho từng phân đoạn cho tới khi mỗi đoạn chỉ còn lại 2 phần tử thì việc sắp xếp kết thúc.
2. Ví dụ
Sắp xếp dãy sau bằng giải thuật Quick Sort:
Chỉ số : 0 1 2 3 4 5 6 7 8 9
Mảng A : 37 11 25 44 55 28 98 84 54 73
Ta chọn chốt đầu tiên là 37. Để tìm 2 khóa cần đổi chỗ cho nhau, ta dùng 2 biến i và j với giá trị ban đầu: i=1, j=9.
Nếu Ai<37 thì tiếp tục tăng i lên 1 và lặp lại, cho tới khi gặp phần tử Ai>37.
Duyệt các phần tử Aj, nếu Aj>37 thì giảm j đi một, cho tới khi gặp phần tử Aj<37.
Nếu i còn nhỏ hơn j thì đổi chỗ Ai và Aj tìm được cho nhau.
Quá trình lặp lại với Ai và Aj cho đến khi i=j, chính là vị trí dành cho khóa 37.
Cuối cùng ta đổi chỗ 37 cho khóa Aj.
Lượt đầu tiên i dừng lại ở A3=44, j dừng lại ở A5=28.
37 11 25 44 55 28 98 84 54 73
Chốt -----I -----j

Đổi chỗ 44 và 28:
37 11 25 28 55 44 98 84 54 73
------------I ---j

Tiếp tục chạy Ai từ 28 và Aj từ 44, i dừng lại ở A4=55, j dừng lại ở A3=28:
37 11 25 28 55 44 98 84 54 73
----------J-- i
Lúc này i>j, ta đổi chỗ chốt 37 cho Aj=28 được:
28 11 25 37 55 44 98 84 54 73
Như vậy kết thúc lần thứ nhất ta được hai đoạn được phân biệt bởi khóa 37 như sau:
28 11 25 [37] 55 44 98 84 54 73

Quá trình được lặp lại tương tự cho từng phân đoạn trên cho tới khi dãy được sắp xếp hoàn toàn
 
Lần chỉnh sửa cuối:
Upvote 0
Em không hiểu ý anh lắm, em lấy 1 ví dụ ngắn gọn thế này !
[GPECODE=vb]
Sub quicksort(subArr(), ByVal L As Long, ByVal U As Long)
Dim i As Long, j As Long
Dim pivot, TG
If L >= U Then Exit Sub <--- Đây là điểm neo, nếu không có điểm này sẽ là vòng lặp vô tận
i = L: j = U
pivot = Int(Rnd() * (j - i + 1) + i)
Do
While subArr(i) < subArr(pivot)
i = i + 1
Wend
While subArr(j) > subArr(pivot)
j = j - 1
Wend
If i <= j Then
TG = subArr(i): subArr(i) = subArr(j): subArr(j) = TG
i = i + 1
j = j - 1
End If
Loop Until i > j
quicksort subArr, L, j <---------- Đệ quy với tham số L,J
quicksort subArr, i, U<---------- Đệ quy với tham số L,J
End Sub
Nếu mà không có 2 tham số L,U thì anh phải tạo thêm 1 điểm neo nữa
[/GPECODE]
Vậy thôi ta tìm cách "quăng" biến ấy ra ngoài ở dạng Public hay gì đó đi
Nói chung là tôi không có khả năng sửa code, chỉ đứng trên QUAN ĐIỂM NGƯỜI DÙNG mà ĐÒI HỎI thôi
Ẹc... Ẹc...
 
Upvote 0
Đây anh
Mã:
Public Sub QuickSort1DArray(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
Em vẫn chưa hiểu biến iLo, iHi để làm gì?
Đứng trên cương vị người dùng thì em chỉ cần thế này:
Mã:
Public Sub QuickSort1DArray(arr, ByVal sortAtoZ As Boolean)
Tức sort mảng nào, và sort tăng dần hay giảm dần
Vậy thôi em nghĩ là đủ rồi
(Hay không còn có ý gì khác về 2 biến trên)

Bạn muốn tìm hiểu code hay bạn muốn dùng? Nếu muốn dùng thì cứ nhập đủ 4 thông số rồi dùng thôi. Ý nghĩa của 4 thông số đó đơn giản như cấu trúc của cái xà beng. Tức cấu trúc của cái xà beng nó đơn giản thế nào thì ý nghĩa của 4 thông số nó cũng đơn giản như vậy. Bạn cứ nhập đủ 4 thông số rồi dùng, cần gì hiểu code? Bản thân bạn đã từng nói: người dùng cứ biết dùng thôi, không cần biết code nó làm gì. Chả nhẽ bạn quên rồi sao?
Nếu muốn biết thêm về 2 thông số "đó", để làm gì, liệu có thể bỏ không, nếu bỏ thì thế nào thì có lẽ thường tình thì người ta sẽ viết: "Tôi muốn biết có thể bỏ 2 thông số iLo và iHi được không. Nếu bỏ thì sửa code thế nào?" Nhưng bạn có hỏi gì đâu? Bạn phán luôn: chưa "gần gũi", "gây lúng túng". Đây không phải là hỏi mà đây là "phán"

Bạn nghĩ 2 thông số là thừa thì bạn có 2 lựa chọn
1. Tự viết code cho mình và bỏ 2 thông số
2. Lấy code của tôi và bỏ 2 thông số.

Nếu bạn chọn 2 và code chạy thì bạn bỏ đi. Thế thôi. Bạn là con người tự do bạn có lựa chọn, không ai ép gì bạn.

Mà tôi không hiểu cái "gây lung tung " của bạn. Cứ cho là thừa đi nhưng vẫn cứ nhập đủ và code chạy thì được việc chứ có gì lung tung nhỉ?

Tất nhiên mỗi người viết một kiểu và có dụng ý của mình. Nếu bạn thấy dùng được thì dùng còn không thì vứt. Bạn biết gì về dụng ý của người khác mà bạn phán này nọ? Bạn muốn dùng thì cứ dùng chứ đâu cần hiểu? Còn nếu tôi có hứng thì tôi sẽ giải thích, không có hứng thì thôi. Cứ nhập đủ mà thấy chạy là được.

Mà tôi tò mò chút. Nhiều người gọi điện cho bạn hoặc nhắn tin phàn nàn về code của tôi thật à? Hoặc khi gặp nhau, đi nhậu họ phàn nàn? Vì bạn viết: "Rất nhiều người lúng túng khi dùng QụickSort của anh siwtom". Nếu đúng thế thì chắc chắn ngay từ đầu họ đã không có nhu cầu hoặc không muốn dùng code của tôi. Vì tôi nghĩ là nếu ai đó có nhu cầu và muốn dùng code của tôi thì họ sẽ hỏi bằng được chứ không phải phàn nàn. Mà hỏi bằng cách gửi tin nhắn cho tôi hoặc hỏi ngay trong chủ đề chứ không phải hỏi bạn. Ai đời lại hỏi người khác thay cho hỏi tác giả?

Chắc chắn nếu ai chỉ dùng thôi thì họ sẽ nhập đủ thông số rồi chạy code. Chả có gì là lúng túng cả.
 
Upvote 0
Em thì hiểu như vậy , không biết có đúng không :
iLo = integer Low, iHi = integer Hight --> tức là chỉ số trên và dưới của một đoạn phần tử trong mảng : Arr(iLo) : Arr(iHi)
* Vì đây là cách viết theo thuật toán đệ quy --> bắt buộc phải có 2 đối số iLo và iHi trong QuickSort

Bạn không phải đoán mò gì cả. Tôi là người có trách nhiệm nên thường giải thích rất kỹ. Cả ý nghĩa của đối số và chú thích cả những chỗ quan trọng trong code. Nếu bạn đọc code thì bạn sẽ thấy ngay trên đầu
Mã:
'    Arr là mảng cần sắp xếp
'    sortAtoZ xác định cách sắp xếp tăng hay giảm
'    iLo là cận dưới của mảng Arr, iHi là cận trên của mảng Arr

Chuyện tác giả viết code như thế nào là chuyện của người ta. Nếu mình thấy dùng được thì dùng còn nếu thấy không hợp lý thì tự viết. Thế thôi. Ai đời lại có chuyện phỉ báng tác giả. Có thể người ta viết thế vì sức của người ta có thế, viết được như thế là cạn kiến thức rồi. Mình không vừa lòng thì vứt đi rồi tự viết. Mà có phỉ báng người ta thì trước tiên hãy tự viết, nếu được hãy phỉ báng.
 
Upvote 0
Vậy thôi ta tìm cách "quăng" biến ấy ra ngoài ở dạng Public hay gì đó đi
Nói chung là tôi không có khả năng sửa code, chỉ đứng trên QUAN ĐIỂM NGƯỜI DÙNG mà ĐÒI HỎI thôi
Ẹc... Ẹc...

Quan điểm người dùng hay quan điểm người muốn tìm hiểu code?
Vì người dùng thì chỉ cần nhập đủ 4 thông số rồi chạy. Anh ta có bắt buộc phải hiểu gì đâu? Gõ 2 thông số kia là cực hình chăng?
Chuyện bạn cho 2 biến kia ra Public thì nó tự có giá trị sao? Hay bạn vẫn phải nhập giá trị cho chúng trước khi gọi hàm?
Mà chuyện cho ra public tôi không xét về mặt lập trình, vd. có 5 hàm kiểu đó thì cho hết thông số của chúng ra biến Public? Nhưng tôi chỉ muốn nói: mỗi người có "thói quen" lập trình của mình. Đừng cho là cách của mình là hay nhất hoặc bắt người khác cũng phải làm như mình.
 
Upvote 0
Hình như tôi cũng đã thấy 2 biến đó nó thừa thừa sao đó, nên đã viết ở bài này:

http://www.giaiphapexcel.com/forum/...nhờ-test-hộ-và-góp-ý&p=521349#post521349

Có thể về nguyên tắc của thuật toán nào đó thì phải bắt buộc như thế, nhưng với VBA của Excel thì không cần, vậy thì ta cứ giản thiểu biến một cách không cần thiết là được chứ nhỉ?

Bạn nghĩ là nó thừa hay bạn chắc chắn là nó thừa? Nếu chắc chắn thì vứt nó đi. Nếu sau đó code không chạy thì tự sửa.
Sức tôi có hạn thôi bạn ạ. Đâu có được như những vĩ nhân, siêu nhân, sư phụ GPE.

Tôi viết code 10 tháng trước. Có lúc nào tôi phàn nàn rằng không ai quan tâm, không ai dùng đâu. Tôi là ai mà có quyền ép mọi người dùng code của mình? Tôi không phàn nàn gì cả. Chỉ tới khi bạn so code của mình với code của huuthang_bd để rồi từ trên đỉnh cao chiến thắng diễu cợt vodoi2x

Thế cho nên đừng ai vỗ ngực xưng tên tôi hay và chê người ta ngớ ngẫn, mà hãy học thêm và biết chọn lọc tinh hoa của người khác mà ứng dụng vô công việc của mình. Bạn có giỏi thì cứ cắt bằng tay đi rồi nghiền nát, còn tôi thì dùng máy xay sinh tố vậy!

tôi mới đưa nó ra cho bạn xem. Thế thôi.

Tôi cũng đã trả lời câu mỉa mai "nó nằm tuốt luốt dưới đáy đại dương" ở chủ đề bên kia

http://www.giaiphapexcel.com/forum/...xếp-mảng-nhờ-test-hộ-và-góp-ý&p=521349
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn nghĩ là nó thừa hay bạn chắc chắn là nó thừa? Nếu chắc chắn thì vứt nó đi. Nếu sau đó code không chạy thì tự sửa.
Sức tôi có hạn thôi bạn ạ. Đâu có được như những vĩ nhân, siêu nhân, sư phụ GPE.

Tôi viết code 10 tháng trước. Có lúc nào tôi phàn nàn rằng không ai quan tâm, không ai dùng đâu. Tôi là ai mà có quyền ép mọi người dùng code của mình? Tôi không phàn nàn gì cả. Chỉ tới khi bạn so code của mình với code của huuthang_bd để rồi từ trên đỉnh cao chiến thắng diễu cợt vodoi2x



tôi mới đưa nó ra cho bạn xem. Thế thôi.

Tôi cũng đã trả lời câu mỉa mai "nó nằm tuốt luốt dưới đáy đại dương" ở chủ đề bên kia

http://www.giaiphapexcel.com/forum/...xếp-mảng-nhờ-test-hộ-và-góp-ý&p=521349


Trước tiên, em xin nói rõ là em chẳng mỉa mai ai cả, chẳng qua là dùng từ cường điệu thôi, không có gì gọi là mỉa mai nhất là đối với bậc Thầy, bậc tiền bối cả.

Kế tiếp em nói thừa là vì sao, thay vì code thế này:

Mã:
Public Sub QuickSort1DArray(arr, [COLOR=#ff0000][B]iLo As Long, iHi As Long[/B][/COLOR], ByVal sortAtoZ As Boolean)


Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s


    Do
        Lo = iLo
        Hi = iHi
        
        iMid = arr((Lo + Hi) \ 2)
        Do
            If sortAtoZ Then
                Do While arr(Lo) < iMid
                    Lo = Lo + 1
                Loop
                Do While arr(Hi) > iMid
                    Hi = Hi - 1
                Loop
            Else
                Do While arr(Lo) > iMid
                    Lo = Lo + 1
                Loop
                Do While arr(Hi) < iMid
                    Hi = Hi - 1
                Loop
            End If
            
            If Lo <= Hi Then
                If sortAtoZ Then
                    DoChange = (arr(Lo) > arr(Hi))
                Else
                    DoChange = (arr(Lo) < arr(Hi))
                End If
                If DoChange Then
                    s = arr(Lo)
                    arr(Lo) = arr(Hi)
                    arr(Hi) = s
                End If
                
                Lo = Lo + 1
                Hi = Hi - 1
            End If
        Loop Until Lo > Hi
        If Hi > iLo Then QuickSort1DArray arr, iLo, Hi, sortAtoZ
        iLo = Lo
    Loop Until Lo >= iHi
End Sub

Và người sử dụng sẽ xài như thế này:

QuickSort1DArray UserArr, Lbound(UserArr), Ubound(UserArr), True/False

Thì người viết code có thể thay đổi chút đỉnh cho người dùng cảm thấy tiện lợi hơn như thế này:

Mã:
Public Sub QuickSort1DArray(arr, ByVal sortAtoZ As Boolean)
[COLOR=#000000]
[/COLOR][COLOR=#ff0000][B]Dim iLo As Long, iHi As Long
iLo = LBound(Arr): iHi = UBound(Arr)[/B][/COLOR]

Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s


    Do
        Lo = iLo
        Hi = iHi
        
        iMid = arr((Lo + Hi) \ 2)
        Do
            If sortAtoZ Then
                Do While arr(Lo) < iMid
                    Lo = Lo + 1
                Loop
                Do While arr(Hi) > iMid
                    Hi = Hi - 1
                Loop
            Else
                Do While arr(Lo) > iMid
                    Lo = Lo + 1
                Loop
                Do While arr(Hi) < iMid
                    Hi = Hi - 1
                Loop
            End If
            
            If Lo <= Hi Then
                If sortAtoZ Then
                    DoChange = (arr(Lo) > arr(Hi))
                Else
                    DoChange = (arr(Lo) < arr(Hi))
                End If
                If DoChange Then
                    s = arr(Lo)
                    arr(Lo) = arr(Hi)
                    arr(Hi) = s
                End If
                
                Lo = Lo + 1
                Hi = Hi - 1
            End If
        Loop Until Lo > Hi
        If Hi > iLo Then QuickSort1DArray arr, iLo, Hi, sortAtoZ
        iLo = Lo
    Loop Until Lo >= iHi
End Sub

Và cấu trúc đó, người dùng chỉ cần biết mảng đầu vào và chiều sort thôi:

QuickSort1DArray UserArr, True/False

Phải chăng là tiên lợi hơn chăng? Có ảnh hưởng gì đến code không?

Thầy góp ý cho em thì em rất vui lòng đón nhận vì kiến thức của Thầy rất vĩ đại, chẳng lẽ một góp ý cỏn con vậy mà Thầy lại khó chịu đến thế hay sao?
 
Upvote 0
Bạn không phải đoán mò gì cả. Tôi là người có trách nhiệm nên thường giải thích rất kỹ. Cả ý nghĩa của đối số và chú thích cả những chỗ quan trọng trong code. Nếu bạn đọc code thì bạn sẽ thấy ngay trên đầu
Mã:
'    Arr là mảng cần sắp xếp
'    sortAtoZ xác định cách sắp xếp tăng hay giảm
'    iLo là cận dưới của mảng Arr, iHi là cận trên của mảng Arr

Chuyện tác giả viết code như thế nào là chuyện của người ta. Nếu mình thấy dùng được thì dùng còn nếu thấy không hợp lý thì tự viết. Thế thôi. Ai đời lại có chuyện phỉ báng tác giả. Có thể người ta viết thế vì sức của người ta có thế, viết được như thế là cạn kiến thức rồi. Mình không vừa lòng thì vứt đi rồi tự viết. Mà có phỉ báng người ta thì trước tiên hãy tự viết, nếu được hãy phỉ báng.
Hix tại code bài #833 có đoạn này em không dịch được nên mới hỏi là " không biết có đúng không ?" chứ em có "đoán mò " theo ý hiểu của anh đâu :?
Mã:
Trích từ code bài #833
Public Sub QuickSort1DArray(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
'    Arr laE maNng câEn saep xeep
'    sortAtoZ xaec dinnh caech saep xeep tang hay giaNm
'    iLo laE cânn dýoei cuNa maNng Arr, iHi laE cânn tren cuNa maNng Arr
Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s
 
Lần chỉnh sửa cuối:
Upvote 0
Và cấu trúc đó, người dùng chỉ cần biết mảng đầu vào và chiều sort thôi:

QuickSort1DArray UserArr, True/False

Phải chăng là tiên lợi hơn chăng? Có ảnh hưởng gì đến code không?

Thì bạn tự bỏ đi rồi chạy code thì biết thôi chứ cần gì phải hỏi ai?

Thầy góp ý cho em thì em rất vui lòng đón nhận vì kiến thức của Thầy rất vĩ đại

Bạn nói quá. Sức mỗi người là có giới hạn.
Nếu gõ 2 thông số đối với bạn là cực hình thì đừng dùng code, thế thôi. Tôi cũng chả có hứng gì xem lại code. Cũng có thể tôi không giải quyết được. Chuyện dễ hiểu.
 
Upvote 0
Trước tiên, em xin nói rõ là em chẳng mỉa mai ai cả, chẳng qua là dùng từ cường điệu thôi, không có gì gọi là mỉa mai nhất là đối với bậc Thầy, bậc tiền bối cả.

Kế tiếp em nói thừa là vì sao, thay vì code thế này:

Và người sử dụng sẽ xài như thế này:

QuickSort1DArray UserArr, Lbound(UserArr), Ubound(UserArr), True/False

Thì người viết code có thể thay đổi chút đỉnh cho người dùng cảm thấy tiện lợi hơn như thế này:

Mã:
Public Sub QuickSort1DArray(arr, ByVal sortAtoZ As Boolean)
[COLOR=#000000]
[/COLOR][COLOR=#ff0000][B]Dim iLo As Long, iHi As Long
iLo = LBound(Arr): iHi = UBound(Arr)[/B][/COLOR]

Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s


    Do
        Lo = iLo
        Hi = iHi
        
        iMid = arr((Lo + Hi) \ 2)
        Do
            If sortAtoZ Then
                Do While arr(Lo) < iMid
                    Lo = Lo + 1
                Loop
                Do While arr(Hi) > iMid
                    Hi = Hi - 1
                Loop
            Else
                Do While arr(Lo) > iMid
                    Lo = Lo + 1
                Loop
                Do While arr(Hi) < iMid
                    Hi = Hi - 1
                Loop
            End If
            
            If Lo <= Hi Then
                If sortAtoZ Then
                    DoChange = (arr(Lo) > arr(Hi))
                Else
                    DoChange = (arr(Lo) < arr(Hi))
                End If
                If DoChange Then
                    s = arr(Lo)
                    arr(Lo) = arr(Hi)
                    arr(Hi) = s
                End If
                
                Lo = Lo + 1
                Hi = Hi - 1
            End If
        Loop Until Lo > Hi
        If Hi > iLo Then [COLOR=#ff0000]QuickSort1DArray arr , sortAtoZ[/COLOR]
        iLo = Lo
    Loop Until Lo >= iHi
End Sub

Và cấu trúc đó, người dùng chỉ cần biết mảng đầu vào và chiều sort thôi:

QuickSort1DArray UserArr, True/False

Phải chăng là tiên lợi hơn chăng? Có ảnh hưởng gì đến code không?

Thầy góp ý cho em thì em rất vui lòng đón nhận vì kiến thức của Thầy rất vĩ đại, chẳng lẽ một góp ý cỏn con vậy mà Thầy lại khó chịu đến thế hay sao?

Nếu anh sửa code vậy thì có vẻ không ổn : anh test thử xem :
Mã:
Arr = Array(1, 4, 3, 2, 0, 99, 1, 2, 4, 9, 456, 12)
 QuickSort1DArray Arr, False
 
Upvote 0
Hix tại code bài #833 có đoạn này em không dịch được nên mới hỏi là " không biết có đúng không ?" chứ em có "đoán mò " theo ý hiểu của anh đâu :?
Mã:
Public Sub QuickSort1DArray(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
'    Arr laE maNng câEn saep xeep
'    sortAtoZ xaec dinnh caech saep xeep tang hay giaNm
'    iLo laE cânn dýoei cuNa maNng Arr, iHi laE cânn tren cuNa maNng Arr
Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s

Đó là copy từ VBE ra. Tôi cũng quên không dịch sang unicode.
Nhưng ở chủ đề "kia" tôi có hướng dẫn cách hiển thị ghi chú trong VBE
 
Upvote 0
Nếu anh sửa code vậy thì có vẻ không ổn : anh test thử xem :
Mã:
Arr = Array(1, 4, 3, 2, 0, 99, 1, 2, 4, 9, 456, 12)
 QuickSort1DArray Arr, False


Ơ lạ nhỉ?
Tôi có sửa gì đâu? Tự bạn đề nghị và tự bạn sửa. Tôi chỉ nói là: để biết code sau khi sửa có chạy không thì không cần phải hỏi ai cả. Thế thôi.
 
Upvote 0
Ơ lạ nhỉ?
Tôi có sửa gì đâu? Tự bạn đề nghị và tự bạn sửa. Tôi chỉ nói là: để biết code sau khi sửa có chạy không thì không cần phải hỏi ai cả. Thế thôi.

Hix cái vụ này là ý em muốn nhắn tới anh nghĩa với nội dung sau :
Nếu anh định viết theo kiểu dim iLo..... thì anh nên test trước khi post bài ,xem code có hoạt động không thôi !

Em lại bị oan rồi !$@!!
 
Upvote 0
Hix cái vụ này là ý em muốn nhắn tới anh nghĩa với nội dung sau :
Nếu anh định viết theo kiểu dim iLo..... thì anh nên test trước khi post bài ,xem code có hoạt động không thôi !

Em lại bị oan rồi !$@!!

Ôi, ngàn lần xin lỗi.
Tôi cứ tưởng đấy là bài Hoàng Trọng Nghĩa trả lời tôi. Bây giờ xem lại thì là bài bạn trả lời Hoàng Trọng Nghĩa. Tức "anh sửa" ở bài là nói tới Nghĩa.
Tôi lại lầm là "anh sửa" là Nghĩa nói với tôi.

Chuyện không dính dáng tới tôi thì thôi.
Một lần nữa xin lỗi bạn

Nói thế thôi chứ tôi cứ thấy ở đâu choảng nhau là tôi biến. Đứng xem nhiều khi một hoặc hai bên tung chưởng trượt thì lại trúng mình. He he.
 
Lần chỉnh sửa cuối:
Upvote 0
Đó là copy từ VBE ra. Tôi cũng quên không dịch sang unicode.
Nhưng ở chủ đề "kia" tôi có hướng dẫn cách hiển thị ghi chú trong VBE

OK, có lẽ lần đầu tiên tôi thấy Sub chạy trong chính Sub đó nên tôi thắc mắc như thế, nếu đã đóng gói như là thư viện và chẳng thấy được mã nguồn thì thôi, còn đằng này thấy được mã nguồn và thắc mắc thì cũng là chuyện rất bình thường, nhưng qua đó sẽ được biết thêm về thủ tục này.

Như thế, tôi tự nhận khuyết điểm là "Có mắt mà không nhìn thấy Thái Sơn".
 
Upvote 0
QuickSort là một trong những bài toán căn bản của lập trình.
Người nào học về thuật toán lập trình đều có học qua nó. Và bao nhiêu năm nay nó vẫn được viết với tham số như vậy, chả giảm thiểu được gì cả.

Lý do không thể dùng biến public/global (biến toàn cục):
- Về cách áp dụng: đây là hàm căn bản để dùng làm hàm thư viện. Theo nguyên tắc, hàm thư viện không được dùng biến toàn cục.
- Về cơ cấu code: đây là bài toán đệ quy, mà lại là đệ quy phi tuyến - tức là chính nó chẻ ra để gọi lại nó nhiều lần. Dùng biến toàn cục rất rắc rối và dễ sai.

Theo lệ thường, người ta chỉ dùng biến toàn cục khi sợ bị hết bộ nhớ cho ngăn xếp (stack). Nhưng đã sợ không đủ bộ nhớ thì đừng dùng hàm đệ quy nagy từ đầu.
 
Upvote 0
- Về cơ cấu code: đây là bài toán đệ quy, mà lại là đệ quy phi tuyến - tức là chính nó chẻ ra để gọi lại nó nhiều lần. Dùng biến toàn cục rất rắc rối và dễ sai.

Tôi thấy là chả có lý do chính đáng nào để mà phải làm cho code nó phức tạp lên nên viết như vậy.
Nếu chuyện gõ thêm 2 thông số là việc làm hàng ngày, và mỗi ngày gõ 1000 lần thì tôi còn hiểu được đó là cực hình. Còn không thì không lý gì lại làm phức tạp code để chiều các vị lười. Vì chuyện gõ 2 thông số không phải là cực hình, cũng không là việc gây lúng túng cho người dùng. Gõ gõ thì có gì mà lúng túng.

Còn cứ muốn gõ ít thôi, và chỉ yêu sách duy nhất về chuyện gõ thêm thôi thì có khó gì?

code cho những người ngại gõ
Mã:
Private Sub QuickSort(Arr, iLo As Long, iHi As Long, ByVal sortAtoZ As Boolean)
'    Arr laĚ maŇng câĚn săěp xęěp
'    sortAtoZ xaěc điňnh caěch săěp xęěp tăng hay giaŇm
'    iLo laĚ câňn dýőěi cuŇa maŇng Arr, iHi laĚ câňn tręn cuŇa maŇng Arr
Dim Lo As Long, Hi As Long, iMid, DoChange As Boolean, s

    Do
        Lo = iLo
        Hi = iHi
        
        iMid = Arr((Lo + Hi) \ 2)
        Do
            If sortAtoZ Then
                Do While Arr(Lo) < iMid
                    Lo = Lo + 1
                Loop
                Do While Arr(Hi) > iMid
                    Hi = Hi - 1
                Loop
            Else
                Do While Arr(Lo) > iMid
                    Lo = Lo + 1
                Loop
                Do While Arr(Hi) < iMid
                    Hi = Hi - 1
                Loop
            End If
            
            If Lo <= Hi Then
                If sortAtoZ Then
                    DoChange = (Arr(Lo) > Arr(Hi))
                Else
                    DoChange = (Arr(Lo) < Arr(Hi))
                End If
                If DoChange Then
                    s = Arr(Lo)
                    Arr(Lo) = Arr(Hi)
                    Arr(Hi) = s
                End If
                
                Lo = Lo + 1
                Hi = Hi - 1
            End If
        Loop Until Lo > Hi
        If Hi > iLo Then QuickSort Arr, iLo, Hi, sortAtoZ
        iLo = Lo
    Loop Until Lo >= iHi
End Sub

Public Sub QuickSort1DArray(Arr, ByVal sortAtoZ As Boolean)
    QuickSort Arr, LBound(Arr), UBound(Arr), sortAtoZ
End Sub
 
Upvote 0
Tôi thấy là chả có lý do chính đáng nào để mà phải làm cho code nó phức tạp lên nên viết như vậy.
Nếu chuyện gõ thêm 2 thông số là việc làm hàng ngày, và mỗi ngày gõ 1000 lần thì tôi còn hiểu được đó là cực hình. Còn không thì không lý gì lại làm phức tạp code để chiều các vị lười. Vì chuyện gõ 2 thông số không phải là cực hình, cũng không là việc gây lúng túng cho người dùng. Gõ gõ thì có gì mà lúng túng.

Còn cứ muốn gõ ít thôi, và chỉ yêu sách duy nhất về chuyện gõ thêm thôi thì có khó gì?

code cho những người ngại gõ
Mã:
Public Sub QuickSort1DArray(Arr, ByVal sortAtoZ As Boolean)
    QuickSort Arr, LBound(Arr), UBound(Arr), sortAtoZ
End Sub

Gõ thì không ngại gì đâu Thầy ơi, nhưng với cách này (thêm 1 thủ tục như Thầy vừa làm) thì người dùng họ sẽ thấy "gần gũi" hơn. Giả sử em không biết gì về Ubound, về Lbound hay đại loại là không biết gì về mảng, em chỉ biết chép vào module và chạy code, thấy sướng quá, đem áp dụng luôn, vậy thì kiểu này QuickSort1DArray(Arr, ByVal sortAtoZ As Boolean) người dùng sẽ sướng hơn đấy.

Vì kiến thức em chỉ học lõm tại diễn đàn này, không biết "quái" gì về "bài toán đệ quy hay đệ quy phi tuyến" vì thế làm sao mà biết được cách thức mà biến nó hoạt động như thế nào!

Và vì chả biết gì nên phát biểu linh tinh như thế đấy thôi (điếc không sợ súng là vậy đó Thầy ơi), thông cảm cho em.
 
Upvote 0
Gõ thì không ngại gì đâu Thầy ơi, nhưng với cách này (thêm 1 thủ tục như Thầy vừa làm) thì người dùng họ sẽ thấy "gần gũi" hơn. Giả sử em không biết gì về Ubound, về Lbound hay đại loại là không biết gì về mảng, em chỉ biết chép vào module và chạy code, thấy sướng quá, đem áp dụng luôn, vậy thì kiểu này QuickSort1DArray(Arr, ByVal sortAtoZ As Boolean) người dùng sẽ sướng hơn đấy.

Vì kiến thức em chỉ học lõm tại diễn đàn này, không biết "quái" gì về "bài toán đệ quy hay đệ quy phi tuyến" vì thế làm sao mà biết được cách thức mà biến nó hoạt động như thế nào!

Và vì chả biết gì nên phát biểu linh tinh như thế đấy thôi (điếc không sợ súng là vậy đó Thầy ơi), thông cảm cho em.

Tôi giải thích chút cho bạn hiểu.

Nếu bạn hỏi: "Tôi muốn không phải nhập iLo và iHi có được không? Nếu được thì giải quyết như thế nào?"

Đấy là câu hỏi. Và là câu hỏi thì tôi sẽ trả lời: "không được vì ...", "được, phải sửa lại như thế này ...". Tôi sẽ trả lời như bài #864

Nhưng nếu bạn nói: "Không gần gũi", "gây lúng túng" thì đó có phải câu hỏi không? Rõ ràng không là câu hỏi mà chỉ là một đánh giá.

Khi bạn không hỏi thì chả lẽ gì tôi lại trả lời bạn. Chắc chắn bạn không cần câu trả lời vì nếu cần thì bạn sẽ hỏi. Một khi bạn chỉ đánh giá thôi thì tôi sẽ chỉ trả lời cái đánh giá đó. Không có chuyện "chia sẻ", "vạch đường" gì ở đây. Bạn đánh giá chứ bạn không hỏi, bạn chỉ muốn bình luận thôi, bạn không cần biết gì cả. Nếu thế thì bạn tự sửa hoặc tự viết thôi.

Từ "bạn" tôi dùng ở trên là từ dùng chung chung, không hẳn là bạn. Hoặc hiểu đó là "các bạn".
 
Upvote 0
OK, có lẽ lần đầu tiên tôi thấy Sub chạy trong chính Sub đó nên tôi thắc mắc như thế, ...

Đệ quy có nghĩa là hàm quay đi quay lại. Và có nhiều kiểu đệ quy.

...
Vì kiến thức em chỉ học lõm tại diễn đàn này, không biết "quái" gì về "bài toán đệ quy hay đệ quy phi tuyến" vì thế làm sao mà biết được cách thức mà biến nó hoạt động như thế nào!
...

Đệ quy trực tuyến là gọi lại theo đường thẳng, hàm gọi lại chính nó thẳng tuột một cách trực tiếp - ví dụ hàm tính giai thừa là tiêu biểu; dựa trên công thức n! = n*(n-1)!

Đệ quy phi tuyến không gọi trực tiếp theo đường thẳng mà có thể:
- Tán tuyến: chia ra nhiều nhánh, và lộn lại theo từng nhánh - tiêu biểu là bài quicksort
- Cách tuyến: rất rắc rối, hàm A gọi B, B gọi ngược lại A...
- Hỗn hợp đủ các kiểu trên.
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu bạn chọn 2 và code chạy thì bạn bỏ đi. Thế thôi. Bạn là con người tự do bạn có lựa chọn, không ai ép gì bạn.

Mà tôi không hiểu cái "gây lung tung " của bạn. Cứ cho là thừa đi nhưng vẫn cứ nhập đủ và code chạy thì được việc chứ có gì lung tung nhỉ?

Tất nhiên mỗi người viết một kiểu và có dụng ý của mình. Nếu bạn thấy dùng được thì dùng còn không thì vứt. Bạn biết gì về dụng ý của người khác mà bạn phán này nọ? Bạn muốn dùng thì cứ dùng chứ đâu cần hiểu? Còn nếu tôi có hứng thì tôi sẽ giải thích, không có hứng thì thôi. Cứ nhập đủ mà thấy chạy là được.
Anh siwtom à!
Anh và em quen nhau trên diễn đàn này, thời gian tuy không dài nhưng cũng đủ để anh hiểu được con người em không phải thuộc loại thích bắt bẻ từng câu chữ.
Em tôn trọng anh vì kiến thức của anh... Em HỎI nhằm mục đích để HỌC. Em thấy "lúng túng" thì nói là "lúng túng"
Không ngờ chỉ câu hỏi nhỏ của em lại khiến anh mất bình tỉnh đến vậy
Thôi thì em xin lỗi... Hứa rằng sẽ không hỏi thêm gì nữa
Vậy đi nha!
 
Lần chỉnh sửa cuối:
Upvote 0
Anh siwtom à!
Anh và em quen nhau trên diễn đàn này, thời gian tuy không dài nhưng cũng đủ để anh hiểu được con người em không phải thuộc loại thích bắt bẻ từng câu chữ.
Em tôn trọng anh vì kiến thức của anh... Em HỎI nhằm mục đích để HỌC. Em thấy "lúng túng" thì nói là "lúng túng"
Không ngờ chỉ câu hỏi nhỏ của em lại khiến anh mất bình tỉnh đến vậy
Thôi thì em xin lỗi... Hứa rằng sẽ không hỏi thêm gì nữa

Không, ít nhất là trong bài đầu, Tuấn không hỏi mà là Tuấn đánh giá. Tất nhiên Tuấn "mượn" những người khác "phàn nàn" chứ không phải Tuấn phàn nàn.

Trong bài 843 có 1 câu hỏi. Trong bài 841 và 845 chỉ có những câu khẳng định chứ không có câu hỏi nào. Nếu không có bài 842 của tôi thì sẽ chỉ có 1 bài 841 với lời đánh giá mà thôi. Phải nhìn theo tuần tự lịch sử thì mới biết là hỏi hay đánh giá.


Tôi cũng kết thúc ở đây
 
Lần chỉnh sửa cuối:
Upvote 0
-
Ngoài lề: Có dịp phải phạt ku Nghĩa! Vì cứ bài nào chú mày "khơi mào" là y như rằng có tranh chấp (có hiện tượng nóng lên toàn cầu)...
Chú phải "kiểm điểm" bản thân đi nha (bằng 1 chầu gì đó cũng được)
 
Upvote 0
-
Ngoài lề: Có dịp phải phạt ku Nghĩa! Vì cứ bài nào chú mày "khơi mào" là y như rằng có tranh chấp (có hiện tượng nóng lên toàn cầu)...
Chú phải "kiểm điểm" bản thân đi nha (bằng 1 chầu gì đó cũng được)
Đồng ý với Thầy ndu
Chú Nghĩa chở bạn gái rủ mình & ku Tùng, ku Leo......... đi Biên Hòa kêu ku Thương ra............phạt một bữa
Từ hôm sinh nhật đến nay chưa "óp- iếc" gì cả, nhớ nhớ. À mà ku Nhím về Sì- Gòn chưa nhỉ, chẳng thấy tăm hơi đau cả ??????????
"Chết mẹ", cái này xì- pam rồi
 
Upvote 0
Mã:
Sub Test()
    Dim Arr1, Arr2 As Variant
    Arr1 = Array(1, 2, 3, 4, 5, 6, 7, 10, 11)
    Arr2 = Split("1,2,3,4,5,6,7,10,11", ",")
    QuickSort1DArray Arr1, False
    Debug.Print Join(Arr1, ",")
    QuickSort1DArray Arr2, False
    Debug.Print Join(Arr2, ",")
End Sub

Thủ tục trên, với 2 mảng, cho ra kết quả khác nhau.

Xin hỏi các bạn, bằng cách nào mà hàm QuickSort1DArray nó hiểu đâu là số trong dạng chuỗi để chuyển lại cho đúng là số từ nguồn mảng Split?
 
Upvote 0
Mã:
Sub Test()
    Dim Arr1, Arr2 As Variant
    Arr1 = Array(1, 2, 3, 4, 5, 6, 7, 10, 11)
    Arr2 = Split("1,2,3,4,5,6,7,10,11", ",")
    QuickSort1DArray Arr1, False
    Debug.Print Join(Arr1, ",")
    QuickSort1DArray Arr2, False
    Debug.Print Join(Arr2, ",")
End Sub

Thủ tục trên, với 2 mảng, cho ra kết quả khác nhau.

Xin hỏi các bạn, bằng cách nào mà hàm QuickSort1DArray nó hiểu đâu là số trong dạng chuỗi để chuyển lại cho đúng là số từ nguồn mảng Split?
Như vậy là THÊM VIỆC không cần thiết cho hàm
Nghĩa cứ nghĩ xem: Ngay cả công cụ sort của Excel khi làm việc cũng phân biệt rõ ràng chuổi và số mà
Vậy, muốn nó sort đúng "ý mình" thì cứ chuyển các phần tử của Arr2 thành số trước đi ---> Có tốn công sức gì đâu ---> Vì nếu "chiều ý" của Nghĩa thì hàm sẽ không mang tính tổng quát (mình chú xài)
 
Upvote 0
Như vậy là THÊM VIỆC không cần thiết cho hàm
Nghĩa cứ nghĩ xem: Ngay cả công cụ sort của Excel khi làm việc cũng phân biệt rõ ràng chuổi và số mà
Vậy, muốn nó sort đúng "ý mình" thì cứ chuyển các phần tử của Arr2 thành số trước đi ---> Có tốn công sức gì đâu ---> Vì nếu "chiều ý" của Nghĩa thì hàm sẽ không mang tính tổng quát (mình chú xài)

Tổng quát chứ Thầy, bởi trong một mảng vừa chuỗi vừa số, ta sắp xếp chúng có trật tự hơn vì chúng tự biết đâu là chuỗi, đâu là số dạng chuỗi. Còn việc em đưa ra cái mảng đó mà xử lý thì em đưa trường hợp đó lên đây làm gì nữa Thầy ơi, bởi ngay cái tên Sub đã nói rằng Sort mảng 1 chiều, vậy cái mảng Arr2 chẳng phải là mảng 1 chiều sao? Hay là ta phải ghi chú rằng Sub này sẽ không Sort được chính xác mảng từ hàm Split xuất ra?
 
Lần chỉnh sửa cuối:
Upvote 0
Tổng quát chứ Thầy, bởi trong một mảng vừa chuỗi vừa số, ta sắp xếp chúng có trật tự hơn vì chúng tự biết đâu là chuỗi, đâu là số dạng chuỗi. Còn việc em đưa ra cái mảng đó mà xử lý thì em đưa trường hợp đó lên đây làm gì nữa Thầy ơi, bởi ngay cái tên Sub đã nói rằng Sort mảng 1 chiều, vậy cái mảng Arr2 chẳng phải là mảng 1 chiều sao? Hay là ta phải ghi chú rằng Sub này sẽ không Sort được chính xác mảng từ hàm Split xuất ra?
Bạn thử dòng lệnh này sẽ biết các phần tử của mảng do hàm Split xuất ra có kiểu dữ liệu gì.
Mã:
Debug.Print TypeName(Split("1,2,3", ",")(1))
Đọc từ đầu tới cuối topic này cứ thấy sao sao ấy...
 
Upvote 0
Tổng quát chứ Thầy, bởi trong một mảng vừa chuỗi vừa số, ta sắp xếp chúng có trật tự hơn vì chúng tự biết đâu là chuỗi, đâu là số dạng chuỗi. Còn việc em đưa ra cái mảng đó mà xử lý thì em đưa trường hợp đó lên đây làm gì nữa Thầy ơi, bởi ngay cái tên Sub đã nói rằng Sort mảng 1 chiều, vậy cái mảng Arr2 chẳng phải là mảng 1 chiều sao? Hay là ta phải ghi chú rằng Sub này sẽ không Sort được chính xác mảng từ hàm Split xuất ra?

Nếu bạn nói tới sub của tôi, mà chắc là thế vì trong bài #84 bạn ghi rõ tên, thì tôi trả lời thế này:

1. Bạn nói đúng. Sub này sẽ không Sort được chính xác mảng từ hàm Split xuất ra theo như ý muốn của bạn. Tôi thú nhận như thế bạn đã hài lòng chưa? Bạn có thể quên nó đi được rồi. Bạn có bao nhiêu lựa chọn cơ mà?

2. Sub của tôi sort theo kiểu số nếu mảng vào là mảng toàn số, còn nếu là mảng toàn chuỗi thì sort theo kiểu chuỗi.

Tôi đã viết trong bài #45 là Split trả về mảng chuỗi

Các bạn dùng chuỗi nhưng các bạn lại lại "bắt" 3 < 20, tức coi 3 và 20 như số nên bắt buộc tôi phải sort mảng số. Vì tmp là mảng chuỗi nên tôi phải tạo mảng số Arr
...
For k = 1 To 60000
a = ""
tmp = Split("1,9,1,2,1,8,16,4,3,11,11,9,5,11,12,13,16,15,20,15,14,10,7,20", ",")

vậy kết quả sẽ không dành cho bạn.

Sub của tôi không kiểm tra xem liệu dữ liệu có đổi thành số được không. Cũng không có ý định đổi bất cứ cái gì thành số, thậm chí khi có thể. Có 3 lý do:

a. Tôi cho rằng việc tạo một mảng đúng ý để truyền vào sub là không khó, không mất nhiều thời gian. Chả lý gì sub lại đi làm cái việc không đâu.

b. Tôi là tác giả, dụng ý của tôi là thế. Nếu bạn thấy hay thì dùng, không hay thì bỏ qua. Không ai dí súng vào đầu bạn bắt bạn phải dùng cả.

c. Tôi có ý muốn quái đản thế đấy. Tôi viết theo ý thích của tôi. Tôi có quyền quá đi chứ. Bạn dùng hoặc đá đít nó chứ bạn có quyền gì đòi hỏi. Tôi đã nói là tôi viết thế và không sửa nữa.

Trong chủ đề này tôi đã mất nhiều thời gian. Tôi sẽ không trả lời bạn và bất cứ ai nữa. Dù bạn hay bất cứ ai có viết gì thêm nữa. Chấm hết là hết.
 
Lần chỉnh sửa cuối:
Upvote 0

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

Back
Top Bottom