VBGood网站全文搜索 Google

搜索VBGood全站网页(全文搜索)

VB爱好者乐园(VBGood)

 找回密码
 立即注册
搜索
查看: 12627|回复: 18

VC中的qsort源代码翻译成VB的了

[复制链接]
 楼主| 发表于 2010-4-12 23:35:49 | 显示全部楼层 |阅读模式
如题,下面的代码另存为ISort2.cls就可以了,用法自己研究……

相关链接:http://www.vbgood.com/thread-89774-1-1.html

  1. Option Explicit

  2. #Const UseMSVCRT = 0

  3. #If UseMSVCRT Then

  4. '/***
  5. '*qsort(base, num, wid, comp) - quicksort function for sorting arrays
  6. '*
  7. '*Purpose:
  8. '*   quicksort the array of elements
  9. '*   side effects:  sorts in place
  10. '*   maximum array size is number of elements times size of elements,
  11. '*   but is limited by the virtual address space of the processor
  12. '*
  13. '*Entry:
  14. '*   char *base = pointer to base of array
  15. '*   size_t num  = number of elements in the array
  16. '*   size_t width = width in bytes of each array element
  17. '*   int (*comp)() = pointer to function returning analog of strcmp for
  18. '*           strings, but supplied by user for comparing the array elements.
  19. '*           it accepts 2 pointers to elements.
  20. '*           Returns neg if 1<2, 0 if 1=2, pos if 1>2.
  21. '*
  22. '*Exit:
  23. '*   returns void
  24. '*
  25. '*Exceptions:
  26. '*   Input parameters are validated. Refer to the validation section of the function.
  27. '*
  28. '*******************************************************************************/

  29. Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  30. Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
  31. Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
  32. Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Long) As Long
  33. Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Long, ByVal lpProcName As String) As Long

  34. Private m_bCode(255) As Byte, m_hMod As Long, m_lpFunc As Long
  35. Private m_lpObjPtr As Long, m_nUserData As Long

  36. #End If

  37. Public Function Compare(ByVal Index1 As Long, ByVal Index2 As Long, ByVal nUserData As Long) As Long
  38. 'default implementation (???)
  39. If Index1 < Index2 Then Compare = -1 Else _
  40. If Index1 > Index2 Then Compare = 1 Else Compare = 0
  41. End Function

  42. Friend Sub QuickSort(idxArray() As Long, ByVal nStart As Long, ByVal nEnd As Long, Optional ByVal obj As ISort2, Optional ByVal nUserData As Long, Optional ByVal nLimit As Long = 8)
  43. '///check
  44. If nEnd - nStart <= 1 Then Exit Sub
  45. If obj Is Nothing Then Set obj = Me
  46. '///
  47. #If UseMSVCRT Then
  48. If m_lpFunc Then
  49. m_lpObjPtr = ObjPtr(obj)
  50. m_nUserData = nUserData
  51. CallWindowProc VarPtr(m_bCode(0)), VarPtr(idxArray(nStart)), nEnd - nStart + 1, m_lpFunc, 0
  52. Exit Sub
  53. End If
  54. #Else
  55. '////////////////////////////////TODO:translate qsort.c into VB
  56. Dim i As Long, j As Long, k As Long 'temp
  57. Dim nMid As Long '/* points to middle of subarray */
  58. Dim lpStart As Long, lpEnd As Long '/* traveling pointers for partition step */
  59. Dim nSize As Long '/* size of the sub-array */
  60. Dim nStartStack(31) As Long, nEndStack(31) As Long, nStack As Long '/* stack for saving sub-array to be processed */
  61. '/* this entry point is for pseudo-recursion calling: setting
  62. '   lo and hi and jumping to here is like recursion, but stkptr is
  63. '   preserved, locals aren't, so we preserve stuff on the stack */
  64. Recurse:
  65. 'size = (hi - lo) / width + 1;        /* number of el's to sort */
  66. nSize = nEnd - nStart + 1
  67. '/* below a certain size, it is faster to use a O(n^2) sorting method */
  68. If nSize <= nLimit Then
  69. 'shortsort
  70. If nSize > 1 Then
  71.   Do
  72.    lpStart = nStart
  73.    i = idxArray(lpStart)
  74.    For lpEnd = nStart + 1 To nEnd
  75.     j = idxArray(lpEnd)
  76.     If obj.Compare(j, i, nUserData) > 0 Then lpStart = lpEnd: i = j
  77.    Next lpEnd
  78.    If lpStart < nEnd Then idxArray(lpStart) = idxArray(nEnd): idxArray(nEnd) = i
  79.    nEnd = nEnd - 1
  80.   Loop While nEnd > nStart
  81. End If
  82. Else
  83. '    /* First we pick a partitioning element.  The efficiency of the
  84. '       algorithm demands that we find one that is approximately the median
  85. '       of the values, but also that we select one fast.  We choose the
  86. '       median of the first, middle, and last elements, to avoid bad
  87. '       performance in the face of already sorted data, or data that is made
  88. '       up of multiple sorted runs appended together.  Testing shows that a
  89. '       median-of-three algorithm provides better performance than simply
  90. '       picking the middle element for the latter case. */
  91. '    mid = lo + (size / 2) * width;      /* find middle element */
  92.     nMid = nStart + nSize \ 2
  93. '
  94. '    /* Sort the first, middle, last elements into order */
  95. '    if (__COMPARE(context, lo, mid) > 0) swap(lo, mid, width);
  96.     i = idxArray(nStart): j = idxArray(nMid)
  97.     If obj.Compare(i, j, nUserData) > 0 Then idxArray(nStart) = j: idxArray(nMid) = i
  98. '    if (__COMPARE(context, lo, hi) > 0) swap(lo, hi, width);
  99.     i = idxArray(nStart): j = idxArray(nEnd)
  100.     If obj.Compare(i, j, nUserData) > 0 Then idxArray(nStart) = j: idxArray(nEnd) = i
  101. '    if (__COMPARE(context, mid, hi) > 0) swap(mid, hi, width);
  102.     i = idxArray(nMid): j = idxArray(nEnd)
  103.     If obj.Compare(i, j, nUserData) > 0 Then idxArray(nMid) = j: idxArray(nEnd) = i
  104. '
  105. '    /* We now wish to partition the array into three pieces, one consisting
  106. '       of elements <= partition element, one of elements equal to the
  107. '       partition element, and one of elements > than it.  This is done
  108. '       below; comments indicate conditions established at every step. */
  109. '
  110. '    loguy = lo;
  111. '    higuy = hi;
  112.     lpStart = nStart
  113.     lpEnd = nEnd
  114. '
  115. '    /* Note that higuy decreases and loguy increases on every iteration,
  116. '       so loop must terminate. */
  117. '    for (;;) {
  118.     Do
  119. '        /* lo <= loguy < hi, lo < higuy <= hi,
  120. '           A[i] <= A[mid] for lo <= i <= loguy,
  121. '           A[i] > A[mid] for higuy <= i < hi,
  122. '           A[hi] >= A[mid] */
  123. '
  124. '        /* The doubled loop is to avoid calling comp(mid,mid), since some
  125. '           existing comparison funcs don't work when passed the same
  126. '           value for both pointers. */
  127.         i = idxArray(nMid)
  128. '        if (mid > loguy) {
  129. '            do  {
  130. '                loguy += width;
  131. '            } while (loguy < mid && __COMPARE(context, loguy, mid) <= 0);
  132. '        }
  133.         If nMid > lpStart Then
  134.          Do
  135.           lpStart = lpStart + 1
  136.           j = idxArray(lpStart)
  137.           If lpStart >= nMid Then Exit Do
  138.          Loop While obj.Compare(j, i, nUserData) <= 0
  139.         End If
  140. '        if (mid <= loguy) {
  141. '            do  {
  142. '                loguy += width;
  143. '            } while (loguy <= hi && __COMPARE(context, loguy, mid) <= 0);
  144. '        }
  145.         If nMid <= lpStart Then
  146.          Do
  147.           lpStart = lpStart + 1
  148.           If lpStart > nEnd Then Exit Do
  149.           j = idxArray(lpStart)
  150.          Loop While obj.Compare(j, i, nUserData) <= 0
  151.         End If
  152. '
  153. '        /* lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy,
  154. '           either loguy > hi or A[loguy] > A[mid] */
  155. '
  156. '        do  {
  157. '            higuy -= width;
  158. '        } while (higuy > mid && __COMPARE(context, higuy, mid) > 0);
  159.         Do
  160.          lpEnd = lpEnd - 1
  161.          k = idxArray(lpEnd)
  162.          If lpEnd <= nMid Then Exit Do
  163.         Loop While obj.Compare(k, i, nUserData) > 0
  164. '
  165. '        /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi,
  166. '           either higuy == lo or A[higuy] <= A[mid] */
  167. '
  168. '        if (higuy < loguy)
  169. '            break;
  170.         If lpEnd < lpStart Then Exit Do
  171. '
  172. '        /* if loguy > hi or higuy == lo, then we would have exited, so
  173. '           A[loguy] > A[mid], A[higuy] <= A[mid],
  174. '           loguy <= hi, higuy > lo */
  175. '
  176. '        swap(loguy, higuy, width);
  177.         If lpEnd > lpStart Then idxArray(lpStart) = k: idxArray(lpEnd) = j
  178. '
  179. '        /* If the partition element was moved, follow it.  Only need
  180. '           to check for mid == higuy, since before the swap,
  181. '           A[loguy] > A[mid] implies loguy != mid. */
  182. '
  183. '        if (mid == higuy)
  184. '            mid = loguy;
  185.         If nMid = lpEnd Then nMid = lpStart
  186. '
  187. '        /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top
  188. '           of loop is re-established */
  189. '    }
  190.     Loop
  191. '
  192. '    /*     A[i] <= A[mid] for lo <= i < loguy,
  193. '           A[i] > A[mid] for higuy < i < hi,
  194. '           A[hi] >= A[mid]
  195. '           higuy < loguy
  196. '       implying:
  197. '           higuy == loguy-1
  198. '           or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] */
  199. '
  200. '    /* Find adjacent elements equal to the partition element.  The
  201. '       doubled loop is to avoid calling comp(mid,mid), since some
  202. '       existing comparison funcs don't work when passed the same value
  203. '       for both pointers. */
  204. '
  205. '    higuy += width;
  206.     lpEnd = lpEnd + 1
  207. '    if (mid < higuy) {
  208. '        do  {
  209. '            higuy -= width;
  210. '        } while (higuy > mid && __COMPARE(context, higuy, mid) == 0);
  211. '    }
  212.     i = idxArray(nMid)
  213.     If nMid < lpEnd Then
  214.      Do
  215.       lpEnd = lpEnd - 1
  216.       If lpEnd <= nMid Then Exit Do
  217.      Loop While obj.Compare(idxArray(lpEnd), i, nUserData) = 0
  218.     End If
  219. '    if (mid >= higuy) {
  220. '        do  {
  221. '            higuy -= width;
  222. '        } while (higuy > lo && __COMPARE(context, higuy, mid) == 0);
  223. '    }
  224.     If nMid >= lpEnd Then
  225.      Do
  226.       lpEnd = lpEnd - 1
  227.       If lpEnd <= nStart Then Exit Do
  228.      Loop While obj.Compare(idxArray(lpEnd), i, nUserData) = 0
  229.     End If
  230. '
  231. '    /* OK, now we have the following:
  232. '          higuy < loguy
  233. '          lo <= higuy <= hi
  234. '          A[i]  <= A[mid] for lo <= i <= higuy
  235. '          A[i]  == A[mid] for higuy < i < loguy
  236. '          A[i]  >  A[mid] for loguy <= i < hi
  237. '          A[hi] >= A[mid] */
  238. '
  239. '    /* We've finished the partition, now we want to sort the subarrays
  240. '       [lo, higuy] and [loguy, hi].
  241. '       We do the smaller one first to minimize stack usage.
  242. '       We only sort arrays of length 2 or more.*/
  243. '
  244. '    if ( higuy - lo >= hi - loguy ) {
  245.     If lpEnd - nStart >= nEnd - lpStart Then
  246. '        if (lo < higuy) {
  247. '            lostk[stkptr] = lo;
  248. '            histk[stkptr] = higuy;
  249. '            ++stkptr;
  250. '        }                           /* save big recursion for later */
  251.         If nStart < lpEnd Then
  252.          nStartStack(nStack) = nStart
  253.          nEndStack(nStack) = lpEnd
  254.          nStack = nStack + 1
  255.         End If
  256. '        if (loguy < hi) {
  257. '            lo = loguy;
  258. '            goto recurse;           /* do small recursion */
  259. '        }
  260.         If lpStart < nEnd Then
  261.          nStart = lpStart
  262.          GoTo Recurse
  263.         End If
  264. '    }
  265.     Else
  266. '    else {
  267. '        if (loguy < hi) {
  268. '            lostk[stkptr] = loguy;
  269. '            histk[stkptr] = hi;
  270. '            ++stkptr;               /* save big recursion for later */
  271. '        }
  272.         If lpStart < nEnd Then
  273.          nStartStack(nStack) = lpStart
  274.          nEndStack(nStack) = nEnd
  275.          nStack = nStack + 1
  276.         End If
  277. '
  278. '        if (lo < higuy) {
  279. '            hi = higuy;
  280. '            goto recurse;           /* do small recursion */
  281. '        }
  282.         If nStart < lpEnd Then
  283.          nEnd = lpEnd
  284.          GoTo Recurse
  285.         End If
  286. '    }
  287.     End If
  288. End If
  289. '/* We have sorted the array, except for any pending sorts on the stack.
  290. '   Check if there are any, and do them. */
  291. nStack = nStack - 1
  292. If nStack >= 0 Then
  293. nStart = nStartStack(nStack)
  294. nEnd = nEndStack(nStack)
  295. GoTo Recurse '/* pop subarray from stack */
  296. End If
  297. 'else
  298. '    return;                 /* all subarrays done */
  299. '////////////////////////////////
  300. #End If
  301. End Sub

  302. #If UseMSVCRT Then

  303. Private Sub Class_Initialize()
  304. Dim s As String
  305. '///
  306. m_hMod = LoadLibrary("msvcrt.dll")
  307. m_lpFunc = GetProcAddress(m_hMod, "qsort")
  308. '///
  309. s = "89 E0 E8 00 00 00 00 83 04 24 15 6A 04 FF 70 08" + _
  310. "FF 70 04 FF 50 0C 83 C4 10 C2 10 00 6A 00 89 E0" + _
  311. "8B 15 ObjPtr 50 FF 35 UserData 8B 48 0C" + _
  312. "8B 40 08 FF 31 FF 30 8B 0A 52 FF 51 1C 58 C3"
  313. s = Replace(s, "ObjPtr", ReverseHex(VarPtr(m_lpObjPtr)))
  314. s = Replace(s, "UserData", ReverseHex(VarPtr(m_nUserData)))
  315. CodeFromString s, m_bCode
  316. End Sub

  317. Private Sub Class_Terminate()
  318. FreeLibrary m_hMod
  319. End Sub

  320. Private Sub CodeFromString(ByVal s As String, ByRef b() As Byte)
  321. Dim m As Long, i As Long
  322. s = Replace(s, " ", "")
  323. s = Replace(s, ",", "")
  324. m = Len(s) \ 2
  325. For i = 0 To m - 1
  326. b(i) = Val("&H" + Mid(s, i + i + 1, 2))
  327. Next i
  328. End Sub

  329. Private Function ReverseHex(ByVal n As Long) As String
  330. Dim s As String
  331. s = Right("00000000" + Hex(n), 8)
  332. ReverseHex = Mid(s, 7, 2) + Mid(s, 5, 2) + Mid(s, 3, 2) + Mid(s, 1, 2)
  333. End Function

  334. #End If


复制代码

点评

Jen
我测试好像比其他的算法x10倍时间?  发表于 2015-5-20 17:33

评分

参与人数 4威望 +37 金钱 +8 人气 +5 收起 理由
junyuqin + 8 + 1 谢谢分享~
lekj + 5 + 1 精品文章
仙剑魔 + 12 + 3 连汇编都用上了...
VBProFan + 12 + 8 精品文章

查看全部评分

本帖被以下淘专辑推荐:

 楼主| 发表于 2010-4-12 23:37:16 | 显示全部楼层
Form1.frm 示例代码:
  1. Option Explicit

  2. Implements ISort2

  3. Private Sub Command1_Click()
  4. Dim obj As New ISort2
  5. Dim n() As Long
  6. Dim i As Long, m As Long
  7. m = 50
  8. ReDim n(1 To m)
  9. For i = 1 To m
  10. n(i) = 10000 * Rnd
  11. Debug.Print n(i);
  12. Next i
  13. Debug.Print
  14. obj.QuickSort n, 1, m, Me, 0
  15. For i = 1 To m
  16. Debug.Print n(i);
  17. If i > 1 Then Debug.Assert n(i - 1) >= n(i)
  18. Next i
  19. Debug.Print
  20. End Sub

  21. Private Function ISort2_Compare(ByVal Index1 As Long, ByVal Index2 As Long, ByVal nUserData As Long) As Long
  22. If Index1 > Index2 Then ISort2_Compare = -1 Else _
  23. If Index1 < Index2 Then ISort2_Compare = 1 Else ISort2_Compare = 0
  24. End Function
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-4-12 23:38:08 | 显示全部楼层
还有一个编译选项UseMSVCRT,如果设置成1的话就是调用msvcrt.dll的qsort函数,运行速度估计比VB内部快一点……
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2010-4-13 10:43:08 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

发表于 2010-4-13 11:31:33 | 显示全部楼层
谢谢分享~
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-4-13 12:05:06 | 显示全部楼层
连汇编都用上了...
那个汇编不是快速排序的一部分,是为了调用cdecl的qsort函数和使用cdecl回调而写的……
回复 支持 反对

使用道具 举报

发表于 2010-4-13 12:25:37 | 显示全部楼层
6# acme_pjz

很好很先进
回复 支持 反对

使用道具 举报

发表于 2010-4-13 16:31:10 | 显示全部楼层
好像是传说中的VB+VC编程...不过VC怎么是注释... -_-!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-4-13 17:55:54 | 显示全部楼层
8# download

你什么眼神啊……我不是说“翻译成VB”的了么……注释的那些表示相应的C代码……
回复 支持 反对

使用道具 举报

发表于 2010-4-13 18:13:22 | 显示全部楼层
only a joke...

MSVBVM60.dll加载时这个msvcrt.dll就加载了.所以下面这个可以改为
m_hMod = LoadLibrary("msvcrt.dll")

'//to

m_hMod = GetModuleHandle("msvcrt.dll")

省了一个DLL引用计数.

前几天发现这个msvcrt.dll好东东好多,我己经用他来实现读取大于4G的视频文件,爽!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

文字版|手机版|小黑屋|VBGood  

GMT+8, 2023-4-1 00:24

VB爱好者乐园(VBGood)
快速回复 返回顶部 返回列表