Bubble Sort logical error VB.NET - vb.net

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?

Related

Shell Sort Algorithm

I am attempting to implement an array using the shell sort algorithm. The program will sort the array and output each element to the Listbox after the button was clicked. However, the first item output is always 0. I have included a piece of my source code and a photo of the form below;
Dim randGen As New Random()
Dim unstArray() As Integer
Dim unstArrayCopy() As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Generates random number to save in array.
Dim i As Integer = CInt(TextBox1.Text)
ReDim unstArray(i)
ReDim unstArrayCopy(i)
For x = 0 To i
unstArray(x) = randGen.Next(1, 10001)
Next
Array.Copy(unstArray, unstArrayCopy, i)
End Sub
Private Sub ShllSrtBtn_Click(sender As Object, e As EventArgs) Handles shllSrtBtn.Click
shellsort(unstArrayCopy, unstArrayCopy.GetUpperBound(0))
End Sub
Sub shellsort(ByRef shellSort() As Integer, ByVal max As Integer)
Dim stopp%, swap%, limit%, temp%, k%
Dim x As Integer = CInt((max / 2) - 1)
Do While x > 0
stopp = 0
limit = max - x
Do While stopp = 0
swap = 0
For k = 0 To limit
If shellSort(k) > shellSort(k + x) Then
temp = shellSort(k)
shellSort(k) = shellSort(k + x)
shellSort(k + x) = temp
swap = k
End If
Next k
limit = swap - x
If swap = 0 Then stopp = 1
Loop
x = CInt(x / 2)
Loop
For i = 0 To shellSort.GetUpperBound(0)
ListBox1.Items.Add(shellSort(i))
Next i
End Sub
The problem is here:
ReDim unstArray(i)
ReDim unstArrayCopy(i)
In VB, when you initialize an array, you must give it the maximum index you want to use, not the intended array length as in other languages like C#.
Because of that, your code creates an array of length i+1, but you only loop from 0 to i when filling the array. So the last element at index i will always be zero.
You should set the initializer in these lines to i-1.
VB Array Reference

Lottery Program - Visual Basic

Have to create a lottery program, getting the random numbers and such easily enough. However I'm stumped. Essentially I have 2 buttons. One to display a checked list box with numbers 1-100, along with the 5 lotto numbers. I have a 2nd button that checks 2 things, to make sure that more than 5 numbers are not checked matching numbers. I'm lost on how to check for a match between the selected numbers between the RNG numbers.
Public Class Form1
Private Sub displayBtn_Click(sender As Object, e As EventArgs) Handles displayBtn.Click
Dim lottoNumbers(5) As Integer
Dim counter As Integer = 0
Dim number As Integer
Dim randomGenerator As New Random(Now.Millisecond)
'This will randomly select 5 unique numbers'
Do While counter < 5
number = randomGenerator.Next(0, 98)
If Array.IndexOf(lottoNumbers, number) = -1 Then
lottoNumbers(counter) = number
counter += 1
End If
Loop
'Display the lottery numbers in the label.'
Label1.Text = String.Empty
Array.Sort(lottoNumbers)
For Each num As Integer In lottoNumbers
Label2.Text = "Lottery Numbers"
Label1.Text &= CStr(num) & " "
Next num
For x = 0 To 98
CheckedListBox1.Items.Add(x + 1)
Next
End Sub
Private Sub checkBtn_Click(sender As Object, e As EventArgs) Handles checkBtn.Click
Dim count As Integer = 0
Dim x As Integer
'Checks to see if user checked more than 5'
For x = 0 To CheckedListBox1.Items.Count - 1
If (CheckedListBox1.CheckedItems.Count > 5) Then
MessageBox.Show("You cannot select more than 5 numbers.")
Return
Else
If (CheckedListBox1.GetItemChecked(x) = True) Then
count = count + 1
ListBox1.Items.Add(CheckedListBox1.Items(x))
End If
End If
Next
End Sub

Finding the average of an array after dropping lowest value? (VB)

I'm developing a program that asks the user to input 5 numbers. The lowest of the 5 numbers will be dropped, and then the other 4 numbers are to be averaged.
I'm quite new to VB, but I believe I'm currently on the right path here...
I've sorted the array to help identify the lowest number, but I do not know how to exclude the lowest number and to then average the other remaining 4.
Here is my code so far:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim IntArr(4) As Integer
Dim i As Integer
For i = 1 To 5
IntArr(4) = InputBox("Enter Number" & i)
Next
Array.Sort(IntArr)
'textbox1.text = ???
End Sub
End Class
Can anyone please assist or at least point me in the right direction?
In keeping with the spirit of your code, something like the following would work.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim IntArr(4) As Integer
Dim OutArr(3) As Integer
For i = 0 To 4
IntArr(i) = InputBox("Enter Number " & i)
Next
Array.Sort(IntArr)
Array.Copy(IntArr, 1, OutArr, 0, 4) 'exclude the lowest number
TextBox1.Text = OutArr.Average()
End Sub
End Class
Using built in LINQ functions
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim numberOfItems = 5
Dim numberOfItemsToRemove = 1
Dim inArray(numberOfItems - 1) As Integer
Dim outArray(numberOfItems - 1 - numberOfItemsToRemove) As Integer
Dim i As Integer
For i = 0 To numberOfItems - 1
While Not Integer.TryParse(InputBox("Enter Number " & i + 1), inArray(i))
MessageBox.Show("Invalid input!")
End While
Next
outArray = inArray.OrderBy(Function(j) j).Skip(numberOfItemsToRemove).ToArray()
MessageBox.Show(
String.Format(
"Input: [{0}], Output: [{1}], average: {2:0.0}",
String.Join(", ", inArray),
String.Join(", ", outArray),
outArray.Average))
End Sub
Your code as it is above will continue to simply change the value of index 4 with each box if I'm not mistaken. I would do something like this (I will use your variable names for your convenience).
Button1_Click(procedure junk that is auto-inserted)
Dim intArr(4) As Integer
Dim OutArr(3) As Integer
Dim intCounter, intAverage, intLowest, intLowIndex As Integer
'populate all indexes of intArr()
For intCounter = 0 to 4
intArr(intCounter) = InputBox("Please enter a number.")
Next intCounter
intCounter = 1 'reset counter for check
intLowest = intArr(intLowIndex) 'start with index 0
'find lowest number and its index
For intCounter = 1 to 4
If intLowest > intArr(intCounter) Then 'defaults to previous
intLowest = intArr(intCounter)
intLowIndex = intCounter
End If
Next intCounter
intCounter = 0 'reset counter again for possible For...Next loops
Select Case intLowIndex
Case = 0
For intCounter = 0 to 3
OutArr(intCounter) = intArr(intCounter + 1)
Next intCounter
Case = 1
OutArr(0) = intArr(0)
OutArr(1) = intArr(2)
OutArr(2) = intArr(3)
OutArr(3) = intArr(4)
Case = 2
OutArr(0) = intArr(0)
OutArr(1) = intArr(1)
OutArr(2) = intArr(3)
OutArr(3) = intArr(4)
Case = 3
OutArr(0) = intArr(0)
OutArr(1) = intArr(1)
OutArr(2) = intArr(2)
OutArr(3) = intArr(4)
Case = 4
For intCounter = 0 to 3
OutArr(intCounter) = intArr(intCounter)
Next intCounter
End Select
intAverage = (OutArr(0) + OutArr(1) + OutArr(2) + OutArr(3)) / 4
'insert your preferred method to display OutArr() and intAverage

Sorted List in Array Visual Basic [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I have a program that creates a list of 25 random numbers from 0 to 1,000. I have to buttons the first button will load a list box with the random numbers and the second button will sort the list of numbers from the smallest to largest which is where I implemented bubble sort code. Now the other list box that is supposed to hold the sorted numbers doesn't work properly it only shows one number instead of all of them.
Here is my code:
Option Strict On
Public Class Form1
Dim rn As Random = New Random
Dim Clicked As Long = 0
Dim numbers, sort As Long
Private Sub GenerateBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GenerateBtn.Click
Clicked += 1
For x = 0 To 25
numbers = rn.Next(0, 1000)
RandomBox.Items.Add(numbers)
If Clicked >= 2 Then
RandomBox.Items.Clear()
Clicked = 1
End If
Next
End Sub
Private Sub SortBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SortBtn.Click
Dim Sorted() As Long = {numbers}
Dim Swapped As Boolean
Dim endOfArray As Integer = Sorted.Length - 1
Dim Tmp As Byte
While (Swapped)
Swapped = False
For I = 0 To endOfArray - 1
If Sorted(I) > Sorted(I + 1) Then
Tmp = CByte(Sorted(I))
Sorted(I) = Sorted(I + 1)
Sorted(I + 1) = Tmp
Swapped = True
End If
endOfArray = endOfArray - 1
Next
End While
SortBox.Items.Clear()
For I = 0 To Sorted.Count - 1
SortBox.Items.Add(Sorted(I))
Next
End Sub
End Class
Change your:
Dim Sorted() As Long = {numbers}
to
Sorted(x) = numbers
edit: Since you changed your code. You need to put back in the line that loads the Sorted Array.
For x = 0 To 25
numbers = rn.Next(0, 1000)
RandomBox.Items.Add(numbers)
Sorted(x) = numbers
If Clicked >= 2 Then
RandomBox.Items.Clear()
Clicked = 1
End If
Next
and remove the:
Dim Sorted() As Long = {numbers}
from the second part and put this declaration back in the beginning like you had:
Dim Sorted(26) as Long
The way you have will only show the latest random number. It is not any array but a single entity. Therefore only the latest will be add into the array. You need to load each number into the array as you create each one. Thus the (x) which loads it into position x.
You didn't use any arrays at all in your project...you're using the ListBox as your storage medium and that's a really bad practice.
I recommend you set it up like this instead:
Public Class Form1
Private rn As New Random
Private numbers(24) As Integer ' 0 to 24 = 25 length
Private Sub GenerateBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GenerateBtn.Click
For x As Integer = 0 To numbers.Length - 1
numbers(x) = rn.Next(0, 1000)
Next
' reset the listbox datasource to view the random numbers
RandomBox.DataSource = Nothing
RandomBox.DataSource = numbers
' empty out the sorted listbox
SortBox.DataSource = Nothing
End Sub
Private Sub SortBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SortBtn.Click
' make a COPY of the original array that we will sort:
Dim sorted(numbers.Length - 1) As Integer
Array.Copy(numbers, sorted, numbers.Length)
Dim Swapped As Boolean = True
Dim endOfArray As Integer = Sorted.Length - 1
Dim Tmp As Integer
While (Swapped)
Swapped = False
For I As Integer = 0 To endOfArray - 1
If sorted(I) > sorted(I + 1) Then
Tmp = sorted(I)
sorted(I) = sorted(I + 1)
sorted(I + 1) = Tmp
Swapped = True
End If
Next
endOfArray = endOfArray - 1
End While
' reset the listbox datasource to view the sorted numbers
SortBox.DataSource = Nothing
SortBox.DataSource = sorted
End Sub
End Class
Also, note that you were decrementing endOfArray inside your for loop. You should only decrement it after each pass; so outside the for loop, but inside the while loop.
Additionally, you were using a Tmp variable of type Byte, but generating numbers between 0 and 999 (inclusive). The Byte type can only hold values between 0 and 255 (inclusive).
Your Bubble Sort implementation was very close to correct!

Array copy will not work in a if statement or by button click sub

I am trying to make a small log ( string array of 10 ) of time stamps that on a event will move the newest event towards the first string in the array.
Here is a few attempts that I have tried. The only time the array will change is when it is in a timer.
What Iam looking to do is
on a bit change to copy arrayA(1) to array(0). witch will move the string from (1) to (0),(2) to (1),(3) to (2) and the rest of the array. So when the event happens it cascades the strings to make a list of last events (0) would be the 10th event that happened and the (9) would be the first or latest event
Attempt 1
Private Sub RcvTmr_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RcvTmr.Tick
dim SrvUpTimeStgArray(9) as string
If BtnBit = False And OneShot(5) = True Then
OneShot(5) = False
SrvUpTimeStgArray(9) = LAtimeSvrUp.TimeString
For I = 0 To 8
SrvUpTimeStgArray(I) = SrvUpTimeStgArray(I + 1)
Next
LAtimeSvrUp.StopTimer()
End If
ListBox1.DataSource = SrvUpTimeStgArray
End Sub
Then this code to
Private Sub RcvTmr_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RcvTmr.Tick
Dim StringArrayA(9) as string : Dim StringArrayB(9) as string
If OneShot(10) = False Then
OneShot(10) = True
StringArrayA(3) = "testst 33333"
StringArrayA(2) = "testst 22222"
StringArrayA(1) = "testst 11111"
StringArrayA(0) = "testst 00000"
End If
StringArrayA(0) = StringArrayA(1)
If Btn1TestBit Then
counter1 = counter1 + 1
BtnTest3.Text = "worked"
'Call ArrayCopy()
Btn1TestBit = False
StringArrayA(0) = StringArrayA(1)
' The below was alternated with the above line ans also did not work
' Array.Copy(StringArrayA, 1, StringArrayB, 0, 4)
End If
ListBox1.DataSource = StringArrayA
ListBox2.DataSource = StringArrayB
Lacount3.Text = counter1
End Sub
I am missing something so thanks..
Update but It has duplicate strings to the array
This is using the AddLog Sub
If ClientConnBit = False And OneShot(5) = True Then
OneShot(5) = False
AddLog(SrvUpTimeStgArray, "Stopped # " & DateTime.Now.ToString() & "* Up Time " & LAtimeSvrUp.TimeString)
LAtimeSvrUp.StopTimer()
For Each entry As String In SrvUpTimeStgArray
If Not String.IsNullOrEmpty(entry) Then
LBSvrUptimeLog.Items.Add(entry)
End If
Next
'LBSvrUptimeLog.DataSource = SrvUpTimeStgArray
My.Settings.UpTimeString.AddRange(SrvUpTimeStgArray)
My.Settings.Save()
End If
You need to copy the values backward, if you do it forward you'll end up copying the same value everywhere. I suggest you load how to use break point and watch.
This is how it would look like
Sub AddLog(ByVal logAsArray() As String, ByVal newEntry As String)
For index As Integer = logAsArray.Length - 1 To 1 Step -1
logAsArray(index) = logAsArray(index - 1)
Next
logAsArray(0) = newEntry
End Sub
You can also use list instead
Sub AddLog(ByVal logAsList As List(Of String), ByVal newEntry As String)
If logAsList.Count = logAsList.Capacity Then
logAsList.RemoveAt(logAsList.Capacity - 1)
End If
logAsList.Insert(0, newEntry)
End Sub
Here's an example on how to use these functions.
Sub Main()
Dim logAsArray(2) As String
AddLog(logAsArray, "a")
AddLog(logAsArray, "b")
AddLog(logAsArray, "c")
AddLog(logAsArray, DateTime.Now.ToString())
For Each entry As String In logAsArray
Console.WriteLine(entry)
Next
Dim logAsList As New List(Of String)(3)
AddLog(logAsList, "a")
AddLog(logAsList, "b")
AddLog(logAsList, "c")
AddLog(logAsList, DateTime.Now.ToString())
For Each entry As String In logAsList
Console.WriteLine(entry)
Next
Console.ReadLine()
End Sub