Here is a example how it should look (this is the same example as the code uses)
The code starts to screw up when changing from level 1 to level 2 a huge mess happens I don't understand it at all.
Here is the code
Public Class Node
Public label As Byte
Public visited As Boolean = False
Public level As Integer
Public Sub New(ByVal label As Byte, ByVal level As Integer)
Me.label = label
Me.level = level
End Sub
End Class
Public rootNodes As New List(Of Node)
Public nodes As New List(Of Node)
Dim adjMatrix As Byte(,)
Dim setDimensions As Boolean = False
Public Sub connectNode(ByVal start As Node, ByVal endd As Node)
'This method will be called to make connect two nodes
If setDimensions = False Then
ReDim Preserve adjMatrix(999 - 1, 999)
setDimensions = True
End If
Dim startIndex As Integer = nodes.IndexOf(start)
Dim endIndex As Integer = nodes.IndexOf(endd)
adjMatrix(startIndex, endIndex) = 1
adjMatrix(endIndex, startIndex) = 1
End Sub
Private Function getUnvisitedChildNode(ByVal n As Node) As Node
Dim index As Integer = nodes.IndexOf(n)
Dim j As Integer = 0
Do While j < nodes.Count
If adjMatrix(index, j) = 1 AndAlso nodes(j).visited = False Then
Return nodes(j)
End If
j += 1
Loop
Return Nothing
End Function
Private Sub clearNodes()
For Each n As Node In nodes
n.visited = False
Next
End Sub
Private Sub printNode(ByVal n As Node)
Debug.Print(n.label & " ")
End Sub
Public Enum Operation
LessThan = 0
GreaterThan = 1
End Enum
Public Function getPossibleNumbersForFirstByte(ByVal op As Operation, ByVal operationOf As Byte, ByVal numbersAlreadyUsed As List(Of Byte), ByVal totalSize As Long) As List(Of Byte)
Dim possibleNumbers As New List(Of Byte)
Dim tempNumber As Integer = -1
While True
If op = Operation.LessThan Then
tempNumber = IIf(tempNumber = -1, operationOf - 1, tempNumber - 1)
ElseIf op = Operation.GreaterThan Then
tempNumber = IIf(tempNumber = -1, operationOf + 1, tempNumber + 1)
End If
If tempNumber < 1 OrElse tempNumber > totalSize Then
Exit While
End If
If numbersAlreadyUsed Is Nothing OrElse numbersAlreadyUsed.Contains(tempNumber) = False Then
possibleNumbers.Add(tempNumber)
End If
End While
Return possibleNumbers
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
test()
End Sub
Sub test()
'Dim actualNumbers() As Byte = {5, 6, 1, 9, 7, 3, 8, 2, 4, 10}
Dim actualNumberList As New List(Of Byte)
actualNumberList.AddRange({5, 6, 1, 9, 7, 3, 8, 2, 4, 10})
Dim ListofGTLT() As Byte = {1, 0, 1, 0, 0, 1, 0, 1, 1}
Dim firstNumber As Byte = actualNumberList(0)
Dim possibleNumbersToUse As New List(Of Byte)
Dim numbersAlreadyUsed As New List(Of Byte)
For currentLevel = 0 To UBound(ListofGTLT)
'clear visited nodes.
clearNodes()
If currentLevel = 0 Then
'Generates Level 0 of all possible values in the first offset.
possibleNumbersToUse = getPossibleNumbersForFirstByte(ListofGTLT(currentLevel), firstNumber, Nothing, 10)
Dim n As Node
'Generates parent nodes of all possible values in the first offset.
For Each possibleNumber As Byte In possibleNumbersToUse
n = New Node(possibleNumber, 0)
rootNodes.Add(n)
nodes.Add(n)
Next
Else
Dim rootNode As Node
For Each rootNode In rootNodes
'Clear numbers already used.
numbersAlreadyUsed.Clear()
'Set already exists first value (known value).
numbersAlreadyUsed.Add(firstNumber)
If currentLevel = 1 Then
'Gets all the numbers which are possible connections.
possibleNumbersToUse = getPossibleNumbersForFirstByte(ListofGTLT(currentLevel), rootNode.label, numbersAlreadyUsed, 10)
Dim n As Node
'Setup connections with new nodes to root node.
For Each value As Byte In possibleNumbersToUse
n = New Node(value, 1)
nodes.Add(n)
'Debug.Print("[Connection]: " & rootNode.label & " = " & n.label)
connectNode(rootNode, n)
Next
Else
numbersAlreadyUsed.Add(rootNode.label)
Dim child = getUnvisitedChildNode(rootNode)
Do While child IsNot Nothing
Debug.Print("------------------------------------------")
Debug.Print("| Root = " & rootNode.label)
Debug.Print("| Child Level = " & child.level)
Debug.Print("| Child = " & child.label)
Debug.Print("------------------------------------------")
'Add to already existing values the child connection node.
If numbersAlreadyUsed.Contains(child.label) = False Then
If child.level = (currentLevel - 1) Then
'Gets next possible numbers which are possible connections.
possibleNumbersToUse = getPossibleNumbersForFirstByte(ListofGTLT(currentLevel), child.label, numbersAlreadyUsed, 10)
Dim n As Node
'Setup connections with new nodes to child node.
For Each value As Byte In possibleNumbersToUse
n = New Node(value, currentLevel)
nodes.Add(n)
connectNode(child, n)
Next
If child.level = 1 Then
'Finish all the level 1 childs for the current Root Node.
child.visited = True
child = getUnvisitedChildNode(rootNode)
Continue Do
Else
numbersAlreadyUsed.Add(child.label)
child.visited = True
child = getUnvisitedChildNode(child)
Continue Do
End If
Else
numbersAlreadyUsed.Add(child.label)
child.visited = True
child = getUnvisitedChildNode(child)
Continue Do
End If
Else
numbersAlreadyUsed.Add(child.label)
child.visited = True
child = getUnvisitedChildNode(child)
Continue Do
End If
Loop
End If
Next
End If
Next
End Sub
Instead of implementing your own class, using the TreeNode class, which is designed for this, makes your code much easier to understand, and has the added advantage of being native to the TreeView, which means all we have to do is add the base node and call ExpandAll and we have a graphical representation of our tree. Also what you want to do is well suited to a recursive routine. Here's a way that will build the tree structure. Whenever the child nodes are being added it skips any with a value already above it in the tree.
Private Sub btnAnswers_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Declare initial treenode with the value we want.
Dim Tree As New TreeNode("5")
'Declare the string of bits.
Dim input As String = "1001001001"
'Start the recursive routine
CalculateTreeNodes(Tree, input)
'Show the tree
TreeView1.Nodes.Add(Tree)
TreeView1.ExpandAll()h
End Sub
Private Sub CalculateTreeNodes(CurrentNode As TreeNode, directions As String)
If directions = "" Then Return
'Parse the text of the current node as byte
Dim value As Byte = Byte.Parse(CurrentNode.Text)
'Get the direction we want and truncate the string
Dim direction As Directions = CType([Enum].Parse(GetType(Directions), directions(0).ToString), Directions)
If directions.Length > 0 Then
directions = directions.Substring(1)
End If
'Get a list of the values of all the parent nodes above this one.
Dim Values As New List(Of Byte)
GetPrevValues(CurrentNode, Values)
'build our child nodes based on the direction we want.
Select Case direction
Case WindowsApplication7.Directions.Higher
For i As Byte = value + 1 To 10
If Not Values.Contains(i) Then
Dim node As New TreeNode(i.ToString)
CurrentNode.Nodes.Add(node)
'Calculate the children for each node
CalculateTreeNodes(node, directions)
End If
Next
Case WindowsApplication7.Directions.Lower
For i As Byte = 1 To value - 1
If Not Values.Contains(i) Then
Dim node As New TreeNode(i.ToString)
CurrentNode.Nodes.Add(node)
CalculateTreeNodes(node, directions)
End If
Next
End Select
End Sub
'recursive routine to find the parent values.
Private Sub GetPrevValues(CurrentNode As TreeNode, Values As List(Of Byte))
If Not CurrentNode Is Nothing Then
Values.Add(Byte.Parse(CurrentNode.Text))
GetPrevValues(CurrentNode.Parent, Values)
End If
End Sub
End Class
Public Enum Directions
Higher = 1
Lower = 0
End Enum
To find the longest branches you could use a conditional to check if directions is down to one character, then any children will be in the longest branches.
Related
I need your help to prepare data. I am reading a byte array. I make bytes to unsigned integers. I read in different blocks of that array and write the UInt32s in 5 lists in total. The data has been stored compressed; that is, some spaces are missing and I need to fill them up. To make it clear, I made a compilable test project for you and wrote the data into an excel file.
This is the original data. From the left to the right: Sizes, Addresses, Indexes, Number_of_items, Description
You can see that in column C the 2, 3, and 4 are missing. So I select columns C through E, and move them down 3 rows. I fill the gaps with 2, 3, 4 in column C and 1, 1, 1 in the other two columns.
I do this until I reach the end of column B. Columns B, C, D, and E must have the same length.
Where I have a little problem
I fail because a While or For loop evaluates the List.Count property only once. That is, if I add something to a list within the loop, the loop doesn't run often enough. I've provisionally worked around this by writing While True and catching an OutOfRangeException. Maybe someone has a better idea; or even an idea that completely replaces my approach :D
Step № 2
If a row has a 2 in column D, I select columns B through E below the 2, and move the contents down one row (only one, because the difference is 1).
I want to do this until I get to the bottom of the table. This will make all columns the same length.
Again, I have the problem that I use While True and go out using an exception. Does anyone have a better idea?
FormMain.vb
Public NotInheritable Class FormMain
Private Sizes As New List(Of UInt32) From {
58_355UI,
20_270UI,
4_830UI,
4_443UI,
25_177UI,
8_844UI,
4_101UI,
4_200UI,
14_991UI,
12_639UI,
12_894UI,
14_165UI,
12_954UI,
26_670UI,
7_388UI}
Private Addresses As New List(Of UInt32) From {4_323UI, 62_706UI, 83_646UI, 88_935UI, 93_883UI, 128_259UI, 132_718UI,
137_254UI, 152_590UI, 178_485UI, 193_022UI, 206_718UI}
Private Indexes As New List(Of UInt32) From {1UI, 5UI, 6UI, 9UI, 10UI, 12UI}
Private NumberOfItems As New List(Of UInt32) From {1UI, 2UI, 1UI, 2UI, 1UI, 2UI}
Private Description As New List(Of UInt32) From {1UI, 1UI, 1UI, 1UI, 1UI, 1UI}
Private Sub ButtonStart_Click(sender As Object, e As EventArgs) Handles ButtonStart.Click
Dim RopD As New Reprocessing_of_parsed_data(Sizes, Addresses, Indexes, NumberOfItems, Description)
RopD.Fill_gaps()
End Sub
End Class
Reprocessing_of_parsed_data.vb
Public NotInheritable Class Reprocessing_of_parsed_data
Public Property Sizes As New List(Of UInteger)
Public Property Addresses As New List(Of UInteger)
Public Property Indexes As New List(Of UInteger)
Public Property Number_of_items As New List(Of UInteger)
Public Property Description As New List(Of UInteger)
Public Sub New(sizes As List(Of UInt32), addresses As List(Of UInt32), indexes As List(Of UInt32), number_of_items As List(Of UInt32), description As List(Of UInt32))
Me.Sizes = sizes
Me.Addresses = addresses
Me.Indexes = indexes
Me.Number_of_items = number_of_items
Me.Description = description
End Sub
Public Sub Fill_gaps()
Dim counterForAddressesList As Integer = 0
'Dim ListCount As Integer = Indexes.Count - 2
Dim i As Integer = 0
While True 'i < ListCount - 2
Try
Dim delta As Integer = CInt(Indexes(i + 1) - Indexes(i)) - 1
Dim number As UInt32 = Indexes(i)
While delta > 0
number += 1UI
counterForAddressesList += 1
Indexes.Insert(CInt(number) - 1, number)
Number_of_items.Insert(CInt(number) - 1, 1UI)
Description.Insert(CInt(number) - 1, 1UI)
delta -= 1
'ListCount += 1
End While
counterForAddressesList += 1
i += 1
Catch ex As ArgumentOutOfRangeException
Exit While
End Try
End While
' Step 2
Dim j As Integer = 0
While True
Try
If Number_of_items(j) > 1UI Then
Dim delta As Integer = CInt(Number_of_items(j)) - 1
While delta > 0
Addresses.Insert(j + 1, UInteger.MaxValue)
Indexes.Insert(j + 1, UInteger.MaxValue)
Number_of_items.Insert(j + 1, UInteger.MaxValue)
Description.Insert(j + 1, UInteger.MaxValue)
delta -= 1
j += 1
End While
End If
j += 1
Catch ex As ArgumentOutOfRangeException
Exit While
End Try
End While
End Sub
End Class
It is never a good idea to catch an index out of bounds exception in a Try-Catch-statement. Only conditions you are not in control of (often I/O errors) should be handled at runtime. An index being out of bounds is a design error and must be fixed at design time.
I extracted the two steps from Sub Fill_gaps into two new methods to make the code easier to read and test.
Public Sub Fill_gaps() ' A better name would be "Decompress"
PrintTable() 'For testing
FillGaps()
PrintTable() 'For testing
AddMissingNumberOfItems()
PrintTable() 'For testing
End Sub
I also added a method PrintTable for testing
Private Sub PrintTable()
Console.WriteLine()
Console.WriteLine($" A B C D E")
For i = 0 To Sizes.Count - 1
Dim A = Sizes(i)
Dim B = If(i < Addresses.Count, Addresses(i), 0UI)
Dim C = If(i < Indexes.Count, Indexes(i), 0UI)
Dim D = If(i < NumberOfItems.Count, NumberOfItems(i), 0UI)
Dim E = If(i < Description.Count, Description(i), 0UI)
Console.WriteLine($"{A,10}{B,10}{C,10}{D,10}{E,10}")
Next
End Sub
Step 1: fill the gaps (the method is self-explanatory):
Private Sub FillGaps()
' Fill gaps in columns C, D and E.
' The number of Addresses B indicates the total number of indexes.
' Append empty items to C, D and E until the list counts matches the
' expected total number of indexes.
Dim originalIndexCount = Indexes.Count 'Save original count
Do While Indexes.Count < Addresses.Count
Indexes.Add(CUInt(Indexes.Count + 1)) ' Make index 1-based
NumberOfItems.Add(1)
Description.Add(1)
Loop
'Move the rows to where the index indicates.
'We do it backwards to not overwrite existing items.
For i As Integer = originalIndexCount - 1 To 0 Step -1
Dim targetIndex = CInt(Indexes(i)) - 1 ' Subtract 1, indexes are 0-based
If targetIndex <> i Then
' Copy to target position
Indexes(targetIndex) = Indexes(i)
NumberOfItems(targetIndex) = NumberOfItems(i)
Description(targetIndex) = Description(i)
'Clear resp. initialize old row
Indexes(i) = CUInt(i + 1) ' Make index 1-based
NumberOfItems(i) = 1
Description(i) = 1
End If
Next
End Sub
Step 2:
Private Sub AddMissingNumberOfItems()
' Insert empty rows after items with NumberOfItems > 1.
' We do it backwards to not mess up our indexes.
For i As Integer = Indexes.Count - 1 To 0 Step -1
For k As UInteger = 2 To NumberOfItems(i)
Addresses.Insert(i + 1, 0)
Indexes.Insert(i + 1, 0)
NumberOfItems.Insert(i + 1, 0)
Description.Insert(i + 1, 0)
Next
Next
End Sub
If you use the following test list for the descriptions, you will better see which rows have been moved or added
Private Description As New List(Of UInt32) From {2UI, 3UI, 4UI, 5UI, 6UI, 7UI}
I'm relatively new to vb. I have made a structure and now I want to do a bubble sort on the values. I'm unsure on how to call all of the data in the single part of the structure which is also a list.
(module)
module module 1
structure studenttype
dim id as string
dim name as string
end structure
public studentdetails as new list(of studenttype)
(main code)
Private Function bubbleSortbyID(ByVal namelist() As String) As String()
Dim n As Integer = namelist.Length()
Dim swapped As Boolean
Do
swapped = False
For i As Integer = 1 To n - 2
If namelist(i) > namelist(i + 1) Then
Dim temp As String = namelist(i + 1)
namelist(i + 1) = namelist(i)
namelist(i) = temp
swapped = True
End If
Next
Loop Until swapped = False 'no swap made so order Is correct
Return namelist
End Function
Private Sub BtnSort_Click(sender As Object, e As EventArgs) Handles BtnSort.Click
Dim id As String ' it is here I do not how how to call the whole variable
bubbleSortbyID(id)' id remains empty
ClearAndAdd()
End Sub'''
i've got arary of string like this C - F - A - M. i want to create a combination from that with condition:
each other item beside last character has to be combined with last character
there's not allowed a same combination, even the order is different. for example
FC - M
CF - M
if the string array contains >=3 element it will generate 2 & 3 itemset, if 2 element then it will generate only 2 itemset
below is my code. my code generate the result like right part of the picture
my question is what method should i use? is it permutation, combination, or other things?
and in pseudocode, what is my case would be like?
here's my code
Public Class permute
Dim ItemUsed() As Boolean
Dim pno As Long, pString As String
Dim inChars() As Char = {"c", "f", "a", "m"}
Private Sub permute_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Sub Permute(ByVal K As Long)
ReDim ItemUsed(K)
pno = 0
Dim i As Integer
For i = 2 To K
Permutate(i, 1)
tb.Text = K
Next
End Sub
Private Sub Permutate(ByVal K As Long, ByVal pLevel As Long)
Dim i As Long, Perm As String
Perm = pString
For i = 0 To K - 1
If Not ItemUsed(i) Then
If pLevel = 1 Then
pString = inChars(i)
Else
pString += inChars(i)
End If
If pLevel = K Then
pno = pno + 1
Results.Text += _
pno & " " & " = " & " " & pString & vbCrLf
Exit Sub
End If
ItemUsed(i) = True
Permutate(K, pLevel + 1)
ItemUsed(i) = False
pString = Perm
End If
Next
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Permute(tb.Text)
End Sub
Private Sub tb_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb.TextChanged
If tb.Text = "" Then
Results.Text = ""
Else
Permute(tb.Text)
End If
End Sub
End Class
here's the requirement screenshot
and here's the program screenshot
Add this class to your project:
Public NotInheritable Class Permutation
Public Shared Function Create(array As Char()) As List(Of String)
Return Permutation.Create(array, False)
End Function
Public Shared Function Create(array As Char(), sort As Boolean) As List(Of String)
If (array Is Nothing) Then
Throw New ArgumentNullException("array")
ElseIf ((array.Length < 0) OrElse (array.Length > 13)) Then
Throw New ArgumentOutOfRangeException("array")
End If
Dim list As New List(Of String)
Dim n As Integer = array.Length
Permutation.Permute(list, array, 0, array.Length)
If (sort) Then
list.Sort()
End If
Return list
End Function
Private Shared Sub Permute(list As List(Of String), array As Char(), start As Integer, n As Integer)
Permutation.Print(list, array, n)
If (start < n) Then
Dim i, j As Integer
For i = (n - 2) To start Step -1
For j = (i + 1) To (n - 1)
Permutation.Swap(array, i, j)
Permutation.Permute(list, array, (i + 1), n)
Next
Permutation.RotateLeft(array, i, n)
Next
End If
End Sub
Private Shared Sub Print(list As List(Of String), array As Char(), size As Integer)
If (array.Length <> 0) Then
Dim s As Char() = New Char(size - 1) {}
For i As Integer = 0 To (size - 1)
s(i) = array(i)
Next
list.Add(s)
End If
End Sub
Private Shared Sub RotateLeft(array As Char(), start As Integer, n As Integer)
Dim tmp As Char = array(start)
For i As Integer = start To (n - 2)
array(i) = array(i + 1)
Next
array(n - 1) = tmp
End Sub
Private Shared Sub Swap(array As Char(), i As Integer, j As Integer)
Dim tmp As Char
tmp = array(i)
array(i) = array(j)
array(j) = tmp
End Sub
End Class
Because of the Int32.MaxValue limit this class will support levels 1 through 13.
s=1, n=1
s=2, n=2
s=3, n=6
s=4, n=24
s=5, n=120
s=6, n=720
s=7, n=5040
s=8, n=40320
s=9, n=362880
s=10, n=3628800
s=11, n=39916800
s=12, n=479001600
s=13, n=6227020800
Usage:
Me.TextBox1.Text = String.Join(Environment.NewLine, Permutation.Create({"c"c, "f"c, "a"c, "m"c}, sort:=False))
Output:
cfam
cfma
cafm
camf
cmfa
cmaf
fcam
fcma
facm
famc
fmca
fmac
acfm
acmf
afcm
afmc
amcf
amfc
mcfa
mcaf
mfca
mfac
macf
mafc
The class is based on C++ code from the following link:
Calculating Permutations and Job Interview Questions
This seems to be a Combination problem rather than Permutation :
"In mathematics, a combination is a way of selecting several things out of a larger group, where (unlike permutations) order does not matter". [Wikipedia]
Try to solve this by doing Combination to all item in array except the last item. Or in other words, do Combination operations nCk for all k, with
n = size of input array minus the last item
k = size of the output itemset, minimum k is 1 and maximum is n
Then append each Combination result with the last item. Following is the pseudocode code, using C# syntax :p
var input = new char[] {'C', 'F', 'A', 'M'};
//save last char
var lastChar = input[input.Length - 1];
//combinationInput is input member without the last character
var combinationInput = new char[input.Length - 1];
Array.Copy(input, 0, combinationInput, 0, combinationInput.Length);
//generate output with itemset size 1 to combinationInput.Length
for (int i = 1; i <= combinationInput.Length; i++)
{
//generate combination with size i
var combinationOutput = combinationInput.Combinations(i);
foreach (var combinedChar in combinationOutput)
{
//print output as: combinationOutput item + lastChar
Console.WriteLine(string.Join(", ", combinedChar) + ", " + lastChar);
}
}
References :
Array.Copy(...). [How to copy part of an array to another array]
.Combinations(int outputSize) extension method. [How to Generate Combinations of Elements of a List in .NET 4.0]
Thanks for reading - I am using the class below to calculate the CRC32 checksum of a specified file.
My question is how would I go about reporting the progress of file completion (in %) to a progressbar on a different form. I have tried (i / count) * 100 under the New() sub but I am not having any luck, or setting the progress bar with it for that matter. Can anyone help?
Thanks in advance
Steve
Public Class CRC32
Private crc32Table() As Integer
Private Const BUFFER_SIZE As Integer = 1024
Public Function GetCrc32(ByRef stream As System.IO.Stream) As Integer
Dim crc32Result As Integer
crc32Result = &HFFFFFFFF
Dim buffer(BUFFER_SIZE) As Byte
Dim readSize As Integer = BUFFER_SIZE
Dim count As Integer = stream.Read(buffer, 0, readSize)
Dim i As Integer
Dim iLookup As Integer
Do While (count > 0)
For i = 0 To count - 1
iLookup = (crc32Result And &HFF) Xor buffer(i)
crc32Result = ((crc32Result And &HFFFFFF00) \ &H100) And &HFFFFFF
crc32Result = crc32Result Xor crc32Table(iLookup)
Next i
count = stream.Read(buffer, 0, readSize)
Loop
GetCrc32 = Not (crc32Result)
End Function
Public Sub New()
Dim dwPolynomial As Integer = &HEDB88320
Dim i As Integer, j As Integer
ReDim crc32Table(256)
Dim dwCrc As Integer
For i = 0 To 255
Form1.CRCWorker.ReportProgress((i / 255) * 100) 'Report Progress
dwCrc = i
For j = 8 To 1 Step -1
If (dwCrc And 1) Then
dwCrc = ((dwCrc And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
dwCrc = dwCrc Xor dwPolynomial
Else
dwCrc = ((dwCrc And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
End If
Next j
crc32Table(i) = dwCrc
Next i
'file complete
End Sub
End Class
'------------- END CRC32 CLASS--------------
'-------------- START FORM1 --------------------------
Private Sub CRCWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles CRCWorker.DoWork
For i = CurrentInt To dgv.Rows.Count - 1
CRCWorker.ReportProgress(0, i & "/" & Total_Files)
Current_File_Num = (i + 1)
SetControlText(lblCurrentFile, Str(Current_File_Num) & "/" & Total_Files)
result = CheckFile(SFV_Parent_Directory & "\" & dgv.Rows(i).Cells(0).Value, dgv.Rows(i).Cells(1).Value)
Select Case result
Case 0 ' missing file
UpdateRow(i, 2, "MISSING")
'dgv.Rows(i).Cells(2).Value = "MISSING"
Missing_Files = Missing_Files + 1
SetControlText(lblMissingFiles, Str(Missing_Files))
Case 1 ' crc match
UpdateRow(i, 2, "OK")
' dgv.Rows(i).Cells(2).Value = "OK"
Good_Files = Good_Files + 1
SetControlText(lblGoodFiles, Str(Good_Files))
Case 2 'crc bad
UpdateRow(i, 2, "BAD")
' dgv.Rows(i).Cells(2).Value = "BAD"
Bad_Files = Bad_Files + 1
SetControlText(lblBadFiles, Str(Bad_Files))
End Select
If CRCWorker.CancellationPending = True Then
e.Cancel = True
Exit Sub
End If
Next
End Sub
Private Sub CRCWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles CRCWorker.ProgressChanged
Dim val As Integer = e.ProgressPercentage
ProgressBar2.Maximum = 100
ProgressBar2.Value = e.ProgressPercentage
Debug.Print(val)
End Sub
Function CheckFile(ByVal tocheck_filepath As String, ByVal expected_crc As String) As Integer 'returns result of a file check 0 = missing 1 = good 2 = bad
If File.Exists(tocheck_filepath) = False Then
Return 0 'return file missing
End If
Dim f As FileStream = New FileStream(tocheck_filepath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
Dim c As New CRC32()
crc = c.GetCrc32(f)
Dim crcResult As String = "00000000"
crcResult = String.Format("{0:X8}", crc)
f.Close()
End Function
It appears your .ReportProgress() call is in the New() subroutine, which is the part that makes the lookup table for the CRC calculation. The New() subroutine is called once, before the main CRC routine. The main CRC routine is the one that takes up all the time and needs the progress bar.
Shouldn't the progress bar updating be in the GetCrc32() function? Something like this:
Public Function GetCrc32(ByRef stream As System.IO.Stream, _
Optional prbr As ProgressBar = Nothing) As UInteger
Dim crc As UInteger = Not CUInt(0)
Dim buffer(BUFFER_SIZE) As Byte
Dim readSize As Integer = BUFFER_SIZE
Dim left As Long = stream.Length
If Not (prbr Is Nothing) Then ' ProgressBar setup for counting down amount left.
prbr.Maximum = 100
prbr.Minimum = 0
prbr.Value = 100
End If
Dim count As Integer : Do
count = stream.Read(buffer, 0, readSize)
For i As Integer = 0 To count - 1
crc = (crc >> 8) Xor tbl((crc And 255) Xor buffer(i))
Next
If Not (prbr Is Nothing) Then ' ProgressBar updated here
left -= count
prbr.Value = CInt(left * 100 \ stream.Length)
prbr.Refresh()
End If
Loop While count > 0
Return Not crc
End Function
In Windows Forms BackgroundWorker Class is often used to run intensive tasks in another thread and update progress bar without blocking the interface.
Example of using BackgroundWorker in VB.Net
The problem is when you use use the form in your code without instantiating it Form1.CRCWorker.ReportProgress((i / 255) * 100) there is a kind of hidden "auto-instantiation" happening and new instance of Form1 is created each time.
This program suppose to sort records(in arySort) in ascending order by last name(index 1 in aryTemp and aryTemp2) and place the result in the list box over the old, preloaded, unsorted records.
It sorts them strangely, I have to click multiple times the Ascending button to get the actual sort result that I suppose to get from clicking the button once.
Why doesn't it sort items with a single mouse click?
The source:
Public Class Form1
Dim FILE_NAME As String = "Students.txt"
Dim numberOfRecords As Integer 'total number of records
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If System.IO.File.Exists(FILE_NAME) = True Then
Dim objReader As New System.IO.StreamReader(FILE_NAME)
Do While objReader.Peek() <> -1
lstBox.Items.Add(objReader.ReadLine)
numberOfRecords += 1
Loop
objReader.Close()
End If
End Sub
Private Sub btnAscending_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAscending.Click
'load all students into array
Dim arySort(numberOfRecords - 1) As String
Dim aryTemp() As String 'holds first record's last name
Dim aryTemp2() As String 'holds second record's last name
For i = 0 To numberOfRecords - 1
arySort(i) = lstBox.Items(i)
Next
Dim temp As String 'holds temporary record
Dim k As Integer
For i = 0 To arySort.Length - 2
aryTemp = Split(arySort(i), " ")
For k = i + 1 To arySort.Length - 1
aryTemp2 = Split(arySort(k), " ")
If aryTemp(1) < aryTemp2(1) Then
temp = arySort(k)
arySort(k) = arySort(i)
arySort(i) = temp
End If
Next
Next
lstBox.Items.Clear()
numberOfRecords = 0
For i = 0 To arySort.Length - 1
lstBox.Items.Add(arySort(i))
numberOfRecords += 1
Next
End Sub
End Class
If you just need to sort your list (as you say in the comment), don't implement your own sort mechanism but use the one of .NET:
' Define how we want to compare items '
Function compareByLastName(ByVal item1 As String, ByVal item2 As String) As Integer
Return String.Compare(item1.Split(" ")(1), item2.Split(" ")(1))
End Function
Private Sub btnAscending_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAscending.Click
' load all students into array '
Dim arySort(numberOfRecords - 1) As String
For i = 0 To numberOfRecords - 1
arySort(i) = lstBox.Items(i)
Next
' Use built-in .NET magic '
Array.Sort(arySort, AddressOf compareByLastName)
' Write the values back into your list box '
lstBox.Items.Clear()
numberOfRecords = 0
For i = 0 To arySort.Length - 1
lstBox.Items.Add(arySort(i))
numberOfRecords += 1
Next
End Sub
This uses the built-in quicksort algorithm of the .NET class library. Here's the documentation of the method we are using: Array.Sort(T(), Comparison(Of T)).
compare with my working bubble sort:
Public Sub BubbleSort(ByVal arr() As Integer)
Dim flag As Boolean = False
For i As Integer = 0 To arr.Length - 1
For j As Integer = 0 To arr.Length - 2 - i
If arr(j + 1) < arr(j) Then
flag = True
Dim temp As Integer = arr(j)
arr(j) = arr(j + 1)
arr(j + 1) = temp
End If
Next
If flag = False Then Return ' no swaps =>already sorted
Next
End Sub
I see a two major issues with your algorithm:
It's not bubble sort. Bubble sort swaps adjacent elements, i.e., it swaps i with i+1. You, on the other hand, swap some element i with the first j > i where name(i) < name(j). Maybe you should show us, in pseudo code, which algorithm you are actually trying to implement?
aryTemp contains element i and aryTemp2 contains some element j > i. Why do you swap the elements if aryTemp(1) < aryTemp2(1)? Isn't that already the correct order if you want your elements to be sorted ascending?