Displaying the values of a multidimensional array in a MessageBox - c#

I am just now learning about multi-dimensional arrays and message boxes. I am currently have a issue in creating 2 columns in my message box. I can currently get it to print up the random numbers I need, but only in one column. Thanks for the help!
string msg = "";
Random numb = new Random();
int[,] thing = new int[ 10, 2 ];
thing[0, 0] = numb.Next(0,10);
thing[0, 1] = numb.Next(0,10);
thing[1, 0] = numb.Next(0,10);
thing[1, 1] = numb.Next(0,10);
thing[2, 0] = numb.Next(0,10);
thing[2, 1] = numb.Next(0,10);
thing[3, 0] = numb.Next(0,10);
thing[3, 1] = numb.Next(0,10);
thing[4, 0] = numb.Next(0,10);
thing[4, 1] = numb.Next(0,10);
thing[5, 0] = numb.Next(0,10);
thing[5, 1] = numb.Next(0,10);
thing[6, 0] = numb.Next(0,10);
thing[6, 1] = numb.Next(0,10);
thing[7, 0] = numb.Next(0,10);
thing[7, 1] = numb.Next(0,10);
thing[8, 0] = numb.Next(0,10);
thing[8, 1] = numb.Next(0,10);
thing[9, 0] = numb.Next(0,10);
thing[9, 1] = numb.Next(0,10);
foreach (int x in thing)
msg = msg + x + "\n";
MessageBox.Show(msg, "Table");

Change this:
foreach (int x in thing)
msg = msg + x + "\n";
MessageBox.Show(msg, "Table");
To :
for (int i = 0; i < thing.GetLength(0); i++)
msg += String.Format("{0} {1}\n", thing[i, 0], thing[i, 1]);
//msg += thing[i, 0] + " " + thing[i, 1] + "\n";
MessageBox.Show(msg, "Table");
Explanation:
Method GetLength(0) returns length of dimension for our x (it's basically like array.Length for simple array but with specific dimension) and we use i variable and for loop to iterate through it. In y we have only 2 elements so we can just use [0] and [1] indexes as we know there are only two elements there. This explains the line:
msg += thing[i, 0] + " " + thing[i, 1] + "\n";
Be careful with concatenating string like that, as if you don't add this space " " between your numbers compiler will just add them, so element like [33, 10] will be concatenated to string like : "43 \n" instead of "33 10 \n".
P.S.
So let's use String.Format method to make sure it's formatted well :
msg += String.Format("{0} {1}\n", thing[i, 0], thing[i, 1]);

I suspect that this question is a duplicate of an existing one, but I cannot find the appropriate precedent. So maybe we are in need of an answer explaining how to format a two-dimensional array for output. This is such an answer. :)
First thing to keep in mind is that the fact that you are displaying this using MessageBox is only barely relevant. What you are really asking is how to format a two-dimensional array as a string, where that string includes line-breaks between rows in your data, and the columns are lined up in the output. Once you have that string, you can display in any context that uses a fixed-space font (which is actually not the MessageBox…but it is not hard to create your own Form to use as a message box, where you can specify the font used to display the text) and have the output appear as you seem to be asking for.
For example, here's a console program that does what you want:
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
Random random = new Random();
int[,] array = new int[10, 2];
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = random.Next(10);
if (j > 0)
{
sb.Append(", ");
}
sb.Append(array[i, j]);
}
sb.AppendLine();
}
Console.WriteLine(sb);
}
Note that I have consolidated the initialization of the array and the formatting of the values into a single piece of code. I have also used nested for loops to index each individual element in the array; this allows two things:
To initialize the array using loops instead of explicitly writing out each element as you did in your example.
To make it easy to recognize the end of a row in the array so that a line-break can be added to the output.
In your example, your random numbers are only ever a single digit. But if you were to want to format numbers that could vary in their number of digits, you would want to pad the output with spaces for the shorter numbers, so that the numbers in the columns of your output lined up. You can do that by adding a width specifier to the output, like this:
sb.AppendFormat("{0,2}", array[i, j]);
In the above, rather than using the default formatting as the previous code example does, I am explicitly specifying a format (and calling AppendFormat() instead of Append() to do so), and in that explicit format, I have included the text ,2, to indicate that I want the output string to have a minimum width of two characters. The method will add spaces as necessary to ensure that.
I have also changed from simple string concatenation to the use of StringBuilder. In your original example, string concatenation is probably not horrible, but it's also not a good habit to get into. When you are repeatedly appending text in a loop, you should always use StringBuilder. Otherwise, an excessive number of objects may be created, and as well an excessive amount of time spent copying character data may be spent. Using StringBuilder allows the text to be concatenated more efficiently.

Related

unsafe method trouble rewriting it without /unsafe

I have some code that was written in unsafe code.
can somebody help me convert it to normal managed code? I don't know how to do it because i don't understand what it's actually doing. Please educate me on what is happening in here.
public byte[] GetRowData(int row)
{
var buffer = new byte[Cols * 6];
unsafe
{
fixed (byte* lpData = buffer, lpTile = &Data[row * Cols * 6])
{
var lpD = lpData;
var lpT = lpTile;
for (var i = 0; i < Cols; i++, lpD += 6, lpT += 6)
{
lpD[0] = lpT[1];
lpD[1] = lpT[0];
lpD[2] = lpT[3];
lpD[3] = lpT[2];
lpD[4] = lpT[5];
lpD[5] = lpT[4];
}
}
}
return buffer;
}
Pointers. They are arguably the single most fundamental tool of coding. They are also arguably the single most dangerous tool of coding. I have worked with them, and they are like "juggling live handgrenades"
The .NET developers tried their best so you would not have to handle them. And indeed could not handle them by default. If you do need to handle them, you have to dip into unsafe code. unsafe is there to allow the use of that byte pointer byte*.
fixed is a hint for the GarbageCollector: "Do not move this from the memory location as part of your work. You would mess up my code."
Edit:
There is so much wrong and odd with the code, it needed a comment to even figure out what it is doing. So your confusion si expected I will try to explain it with comments:
/*The function signature. row is the only data he does not get from a global source. Because of course he get's half the input from global sources, otherwise it would not be hard enough to read!
It seems to do a combined copy and swap operation. And in batches of 6 elements, for some reason*/
public byte[] GetRowData(int row)
{
//He creates a managed array. It's size is a external value called "Cols" times 6. I hope that at least Cols is a constant, but I doubt it.
//This is also the output variable. Later known as lpData and lpD.
var buffer = new byte[Cols * 6];
//He enters unsafe code, to do his pointer shenanigans.
unsafe
{
//he gets a pointer to the start of the buffer (lpData)
//he gets a pointer to whatever is in "row * Cols * 6" of the global Data Collection. So this is the part where he actually retrieves the INPUT, based on the argument he gave this function.
//If Data[row * Cols * 6] is smaler then Cols * 6/buffer.lenght, he already fucked up.
//He also tells the GC to not optimize those around the memory space. He needs nobody else doing stuff in that area.
fixed (byte* lpData = buffer, lpTile = &Data[row * Cols * 6])
{
//Indexing in arrays with pointers is done with some Pointer Arythmetic: Start Pointer + Index times type width - that is the memory adress you write at.
//This is defintely the part where most people messed up with pointers. Also the only way to do it. And why the .NET Array will do this for you only after sanity checks on the index.
//He makes local copies of the pointers, becaus he will do some of the Arithmethic himself - but not all of it
var lpD = lpData;
var lpT = lpTile;
//A for loop. i is jsut your normal running variable to control how many itterations there will be.
//each itteration he will also count lpD and lpT up by 6, to get the next "batch" of elements.
for (var i = 0; i < Cols; i++, lpD += 6, lpT += 6)
{
//He processes the batch of 6 elements. He copies 6 element from input to output, while also swapping the odd and even elements.
//Mathwise those indexers work out to: Pointer of the array start + i*6 + stated index * element width
lpD[0] = lpT[1];
lpD[1] = lpT[0];
lpD[2] = lpT[3];
lpD[3] = lpT[2];
lpD[4] = lpT[5];
lpD[5] = lpT[4];
}
}
}
//We are back out of unsafe code, the pointers have all gone out of scope and he returns whatever he created there in input, from whatever was in Data[row * Cols * 6]
return buffer;
}
To figure out what this is supposed to do, I would need to know what the elements of Data look like.
The code you have provided is copying data from the memory address lpTile to lpData, that's pretty much it.
To convert it to code which doesn't use unsafe and fixed would be something like this, but only if Data is a byte array, else you will need to use unsafe to fix the object at the Data array's start index sins, say that the array is of type int, in the provided unsafe code the data which is being copied are bytes so, if you will want to do it to a int, you will either have to use unsafe or do shift right (>>) 0, 8, 16 & 24 and get the bytes that way for each int value which is retrieved from the Data array.
If the array is of a struct type which is more "complex" say something like the SYSTEMTIME struct, while it will be possible to get bytes for each field in the struct, it will more than likely give you a headache writing it all out.
This example will only work if Data is a byte array.
var buffer = new byte[Cols * 6];
int b_pos = 0;
int d_pos = (row * Cols * 6);
for (var i = 0; i < Cols; i++, b_pos += 6, d_pos += 6)
{
buffer[b_pos + 0] = Data[d_pos + 1];
buffer[b_pos + 1] = Data[d_pos + 0];
buffer[b_pos + 2] = Data[d_pos + 3];
buffer[b_pos + 3] = Data[d_pos + 2];
buffer[b_pos + 4] = Data[d_pos + 5];
buffer[b_pos + 5] = Data[d_pos + 4];
}
return buffer;
Note that using pointers and unsafe isn't bad, it's there for a reason so, if converting that code to something that isn't unsafe isn't a big issue, I would recommend keeping it that way rather than messing with it. Mind you that quite a bit of code in mscorlib.dll uses pointer, for example the ToCharArray function in the String class, while it may seam to be safe, actually its completely based on pointers and copying data from one memory address to another.
Update
After looking at the code, I realized that it's fixed byte* so the Data array is of type byte.
Here are 2 examples one using fixed and another not, with what is happening in each:
fixed Example:
public unsafe byte[] GetRowData(int row)
{
//The total length which will be used as buffer length, Data array start index multiple & for loop length
int totalLength = (Cols * 6);
//Allocates a byte array of size totalLength
var buffer = new byte[totalLength];
//Gets the memory address of the byte in Data at [row * totalLength]
//which, when moved forwards, leads to the next byte in the Data array i.e. at [(row * totalLength) + 1], because data in a array is sequential.
fixed (byte* dataptr = &Data[row * totalLength])
{
//Does a for loop with the end being totalLength and adding to "i" itself 6 instead of some external variables.
for (var i = 0; i < totalLength; i += 6)
{
//moves data from the fixed address "dataptr" to the byte array "buffer"
buffer[i] = dataptr[i + 1];
buffer[i + 1] = dataptr[i];
buffer[2] = dataptr[i + 3];
buffer[3] = dataptr[i + 2];
buffer[4] = dataptr[i + 5];
buffer[5] = dataptr[i + 4];
}
}
return buffer;
}
Example without fixed
public byte[] GetRowData(int row)
{
//Same as in the above example, the total length.
int totalLength = (Cols * 6);
//Same allocation of the buffer size of totalLength
var buffer = new byte[totalLength];
//The index at which to start moving data from the Data array
int dataStartIndex = (row * totalLength);
//The same for loop as in the above example
for (var i = 0; i < totalLength; i += 6)
{
//Moves data from the Data array at index [dataStartIndex + i + n] to the buffer array.
buffer[i] = Data[dataStartIndex + i + 1];
buffer[i + 1] = Data[dataStartIndex + i];
buffer[2] = Data[dataStartIndex + i + 3];
buffer[3] = Data[dataStartIndex + i + 2];
buffer[4] = Data[dataStartIndex + i + 5];
buffer[5] = Data[dataStartIndex + i + 4];
}
return buffer;
}
Mind you, what I said before about the Data array, if it were not of type byte is true, if it were not one then you would need to use fixed or find a way to get bytes from each variable retrieved from the array but, sins Data is a byte array all of the 3 examples above will work.
These are all array operations. They are walking the pointer through the array so they can use fixed offsets in each case.
Obviously I haven't tested this but my inclination:
for (int loop = 0; loop < Cols; loop++)
{
int Offset = loop * 6;
lpD[Offset + 0] = lpT[Offset + 1];
lpD[Offset + 1] = lpT[Offset + 0];
lpD[Offset + 2] = lpT[Offset + 3];
lpD[Offset + 3] = lpT[Offset + 2];
lpD[Offset + 4] = lpT[Offset + 5];
lpD[Offset + 5] = lpT[Offset + 4];
}
I can't convert the rest of this because we don't have the whole picture here. I'm sure the remaining pointers can be replaced by offsets into the array along the lines of what I did here.
I strongly suspect this is some matrix code that was originally written in C and someone did a minimal-effort port to C#.

How to apply binary search in 2D Arrays?

I have to search a for a name from the array through binary search but, show the corresponding age of the person's name instead. Please no other suggestions, I have to do it with Binary search on 2D arrays.
string[,] persons = new string[4, 2];
persons[0, 0] = "Ana";
persons[0, 1] = "19";
persons[1, 0] = "Ammara";
persons[1, 1] = "20";
persons[2, 0] = "Marilyn";
persons[2, 1] = "40";
persons[3, 0] = "Zacharaia";
persons[3, 1] = "70";
string x = "Zacharia";
int upBound = persons.GetLength(0) - 1;
int lowBound = 0;
while (lowBound <= upBound)
{
int midpoint = lowBound + (upBound - lowBound) / 2;
int result = x.CompareTo(persons[midpoint, 1]);
if (result == midpoint)
{
Console.WriteLine("The value is present at:" + persons[midpoint, 1]);
break;
}
else if (result > midpoint)
{
lowBound = midpoint + 1;
Console.WriteLine("The value is present at:" + persons[lowBound, 1]);
break;
}
else if (result < midpoint)
{
upBound = midpoint - 1;
Console.WriteLine("The value is present at:" + persons[upBound, 1]);
break;
}
}
This code is showing the age of everyone 20. The CompareTo() method is not working.
You have 4 major problems in you code:
1- Use midpoint2, lowBound2 and upBound2 for unclear reason, you should use 0 and 1 instead.
2- As you depend on binary search the key elements must be sorted, so "Ana" must be after "Ammara" although she is younger, but you search with name not age, or change it to another name, like "Aca".
3- result should be compared to 0, < 0 and > 0, it has nothing to do with midpoint.
4- You should use Console.WriteLine and break in the first condition only to let the while continue if the name wasn't found yet.
string[,] persons = new string[4, 2];
persons[0, 0] = "Aca";
persons[0, 1] = "19";
persons[1, 0] = "Ammara";
persons[1, 1] = "20";
persons[2, 0] = "Marilyn";
persons[2, 1] = "40";
persons[3, 0] = "Zach";
persons[3, 1] = "70";
string x = "Aca";
int upBound = persons.GetLength(0) - 1;
int lowBound = 0;
while (lowBound <= upBound)
{
int midpoint = lowBound + (upBound - lowBound) / 2;
int result = x.CompareTo(persons[midpoint, 0]);
if (result == 0)
{
Console.WriteLine("The value is present at:" + persons[midpoint, 1]);
break;
}
else if (result > 0)
{
lowBound = midpoint + 1;
}
else
{
upBound = midpoint - 1;
}
}
There are several problems with your code.
A binary search depends on the data being ordered. Therefore to do a binary search on the names they must be in alphabetical order, however Ammara should come before Ana, not after. However, in this case, you would still be able to successfully search for Zacharaia because it is still after the name at the midpoint.
A problem in the processing code is at the line:
x.CompareTo(persons[midpoint, 1]);
You want to compare the name in x ("Zacharia") with the name at the midpoint position, however persons[##, 1] is the location of a number. You need to use
x.CompareTo(persons[midpoint, 0]);
The CompareTo method returns 0 if the values match, < 0 if the x precedes the value and > 0 if x is after the value. However, you are comparing the result to midpoint which has nothing to do with the relative location of the value. Instead use:
if (result == 0)
{...}
else
{
if(result > 0)
{...}
else//The only possibility is for result to be < 0 so you don't need another if here.
{...}
}
The only time that you have found the value is whe result == 0, however you are writing the answer and breaking out of the while loop for all 3 cases. Only break when you find a match (result ==0).
The name in your array ("Zacharaia") is NOT the same as the name in string x ("Zacharia") therefore you will never find a match.
Ideally, your code should handle never finding a match.
If I am not wrong, you want to search names from the Array/List by binary search. For string, you can use Trie data structure to find a name.
If you are asking the names of the person performing search on their age, then proceed with the ages. First, you need to sort the names according to the ages (increasing or decreasing order). Then perform the binary search.

What is the most performant method for setting a subset of sequential items in a large array?

I am working with camera streams. I bring in 1,228,800 bytes per frame, so efficiency is crucial and nanoseconds per byte add up quickly.
I've come up with some example code below to describe the problem as succinctly as possible without seeming too contrived.
There are plenty of inefficiencies in this example code such as defining variables inside of loops, or dividing the brightness value instead of just using a composite value. These aren't my concern, and are just there to make the example simpler.
What I need advice on is the most performant method in C# for setting 3 sequential values at some determined location in a very large array, such as in the case below where I'm setting BGR to 255 while skipping the 4th byte.
Edit: To clarify, the concerning issue is where I'm reindexing Output for each index that is being set. It seems like there should potentially be some method for not traversing the entire array for each value if I already have the location of the previous item.
// Colors are stored as 4 bytes: BGRX where X is always 0
public byte[] Input = new byte[640 * 480 * 4];
public byte[] Output = new byte[640 * 480 * 4];
public int Threshold = 180;
public void ProcessImage() {
for (int i = 0; i < Input.Length; i += 4) {
var brightness = (Input[i] + Input[i + 1] + Input[i + 2]) / 3; // some value under 255
if (brightness > Threshold) {
// What is the most efficient way possible to do this?
Output[i] = 255 - Input[i];
Output[i + 1] = 255 - Input[i + 1];
Output[i + 2] = 255 - Input[i + 2];
}
else {
Output[i] = Input[i];
Output[i + 1] = Input[i + 1];
Output[i + 2] = Input[i + 2];
}
}
}
This (untested, and unsafe) code should be faster, if all you care about is speed:
public void ProcessImage()
{
int ilength = Input.Length;
Debug.Assert(ilength == Output.Length);
Debug.Assert(ilength%4 == 0);
unsafe
{
GCHandle pinned1 = GCHandle.Alloc(Input, GCHandleType.Pinned);
byte* input = (byte*)pinned1.AddrOfPinnedObject();
GCHandle pinned2 = GCHandle.Alloc(Input, GCHandleType.Pinned);
byte* output = (byte*)pinned2.AddrOfPinnedObject();
for (int i = 0; i < ilength; i += 4)
{
var brightness = (*(input) + *(input + 1) + *(input + 2)) / 3;
if (brightness > Threshold)
{
// What is the most efficient way possible to do this?
(*(output)) = (byte)(255 - *(input));
(*(output+1)) = (byte)(255 - *(input+1));
(*(output+2)) = (byte)(255 - *(input+2));
}
else
{
(*(output)) = *(input);
(*(output + 1)) = *(input + 1);
(*(output + 2)) = *(input + 2);
}
input += 4;
output += 4;
}
pinned1.Free();
pinned2.Free();
}
}
Note that I've incorporate the necessary assumptions at the top of the function. I'd suggest you always do this, but whether you prefer Debug.Assert or some other form of validation is up to you.
If you're happy to carry the 4th byte through, it would be quicker to copy Input to Output first with a block copy, then not to perform the else clause of the branch:
Buffer.BlockCopy(Input,0,Output,0,Input.Length);
for (int i = 0; i < Input.Length; i += 4) {
var brightness = (Input[i] + Input[i + 1] + Input[i + 2]) / 3;
if (brightness > Threshold) {
Output[i] = (byte)(255 - Input[i]);
Output[i + 1] = (byte)(255 - Input[i + 1]);
Output[i + 2] = (byte)(255 - Input[i + 2]);
}
}
In terms of the most performant way of setting a single value to multiple array indicies in c#, I think you're looking at it. There's no non-looping way to set the same value to multiple indicies. See How can I assign a value to multiple array indices at once without looping?
If it helps, there's no need for the else statement where you set the 3 indicies to 0. default(byte) is already zero, so every index in the Ouput[] array will initialize to 0.
As a side note, defining variables inside of loops vs outside of loops has no effect on the resulting IL. See Is it better to declare a variable inside or outside a loop?
EDIT: To add on to the comment above, you can use unsafe methods. See https://stackoverflow.com/a/5375552/3290789 and http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx

Align numbers in RichTextBox

I want to print a multiplication table in C# but it's not aligned!
When we type a number "n" in textbox means: n*n table.
What can I do?
for (int i = 1; i <= Convert.ToInt32(textBox1.Text); i++)
{
for (int j = 1; j <= Convert.ToInt32(textBox1.Text); j++)
{
richTextBox1.Text += Convert.ToString(i * j) + " ";
}
richTextBox1.Text += "\n";
}
Set the font of RichTextBox to the monospaced font Courier New, then add the text to RichTextBox using String.Format and setting alignment for the result of multiplication. Use a positive number to align right and use a negative number to align left:
var n = 5;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
this.richTextBox1.AppendText(string.Format("{0,3}", i * j));
}
this.richTextBox1.AppendText(Environment.NewLine);
}
Instead of format the result by {0,3} you can use below code to format based on maximum length of characters is a number which belongs to n*n:
Left Aligned:
string.Format("{0,-" +((n*n).ToString().Length + 1).ToString() +"}", i * j)
Right Aligned:
string.Format("{0," +((n*n).ToString().Length + 1).ToString() +"}", i * j)
If you want to align using spaces, you need to use a monospaced font (like Courier, or Consolas), otherwise you can use tabs: numbers won't be aligned this way though, and since numbers in your routine can get considerably big, you may end up having your numbers occupy more than the tab separation, and will get inconsistencies in the alignment if that happens.
As a general rule, if you want to align any kind of text box, go with a monospaced font.
You can pad with spaces, using, for example, String.PadLeft or String.PadRight.
This would be as simple as changing:
richTextBox1.Text += Convert.ToString(i * j) + " ";
With
richTextBox1.Text += Convert.ToString(i * j).PadLeft(5);
However this would assume all numbers are at maximum 5 characters in width.
For your precise routine, you could calculate the maximum width though, so you'd end up with something like:
// convert your input only once
int myNumber = Convert.ToInt32(textBox1.Text);
// pad with the maximum possible length, plus one space
int padAmount = (myNumber * myNumber).ToString().Length + 1;
for (int i = 1; i <= myNumber; i++)
{
for (int j = 1; j <= myNumber; j++)
{
// pad your input by the amount of spaces needed to fit all possible numbers
richTextBox1.Text += (i*j).ToString().PadLeft(padAmount);
}
}
// use Environment.NewLine instead of `\n`
richTextBox1.Text += Environment.NewLine;
Here's a fiddle. It's (for obvious reasons) for console, so in my fiddle the input number is fixed (it's in myNumber) and the output is just a string (instead of richTextBox1.Text), but it should show how it works.
Although I've made a few changes (I only convert the input number once, and use Environment.NewLine instead of \n), this is far from optimal though, you should build your string (using a StringBuilder) and assign it at once, instead of adding to the Text property. I've made a fiddle with this approach, and memory consumption has gone down by over 30mb (to just a handful of kb) just by using StringBuilder.
I think the best solution is using a tab instead of a special font and padding with white spaces.
For tabs you must add a "\t" after every number. The "\t" will be evaluated as an tab-character.
for (int i = 1; i <= Convert.ToInt32(textBox1.Text); i++)
{
for (int j = 1; j <= Convert.ToInt32(textBox1.Text); j++)
{
richTextBox1.Text += Convert.ToString(i * j) + "\t "; //here at the end
}
richTextBox1.Text += "\n";
}
But it is important, that a tab has a fixed width. In case your numbers are too long, you need 2 tabs for short numbers. But for small tables like yours it is no problem.
You can change the position of the tabs with the SelectionTabs property:
this.richTextBox1.SelectionTabs = new[] { 20, 40, 60, 80 };
BTW, you should use a StringBuilder to concatenate multiple string parts to one. And it would be more effective to parse the number from textBox1 only once and not during every iteration.
var sb = new StringBuilder(); //In namespace System.Text
var x = Convert.ToInt32(textBox1.Text); //parse only once
for (int i = 1; i <= x; i++)
{
for (int j = 1; j <= x; j++)
{
sb.Append(Convert.ToString(i * j));
sb.Append("\t ");
}
sb.Append("\n");
}
richTextBox1.Text += sb.ToString();

Time complexity of the code below

I am trying to check the time complexity of the below simple program.
The program replaces spaces in a string with '%20'.
The loop to count spaces (O(1) time)
foreach (char k in s)
{
if (k == ' ')
{
spaces_cnt++;
}
}
The loop to replace the spaces (O(n) where n is size of string)
char[] c = new char[s.Length + spaces_cnt * 3];
int i = 0;
int j = 0;
while (i<s.Length)
{
if (s[i] != ' ')
{
c[j] = s[i];
j++;
i++;
}
else
{
c[j] = '%';
c[j + 1] = '2';
c[j + 2] = '0';
j = j + 3;
i++;
}
}
So I am guessing it is a "O(n) + O(1)" solution. Please correct me if I am wrong.
The loop to count spaces takes O(n), not O(1), since you’re iterating over – and performing a check on – each of the n characters in your string.
As you stated, the replacement loop takes O(n). Two O(n) operations performed sequentially have a combined complexity of O(n) (constant factors are discarded in Big-O notation).
P.S. You know that you can achieve the equivalent of all your code using a single line?
s = s.Replace(" ", "%20");
Looks like you're trying to encode a string. If that's the case, you can use the UrlPathEncode() method. If you're only trying to encode spaces, use Replace() (as mentioned by Douglas).

Categories

Resources