Microsoft Interview Question
Software Engineer / Developersmaybe a stupid question, but how would you get to the end in the first place?
if you're doing it w/ a while !eof loop, might be better off having an array w/10 buckets, and an array index i that gets incremented as each line is read until it hits 9, then is reset to 0. then while !eof you read each line into array[i] (i.e. the next empty bucket or the oldest line in a full array.)
this seems inefficient for really long files, but I don't know how you'd go directly to the end...fseek or something? am I missing something simple?
#include "stdio.h"
int main()
{
FILE *fp1 = fopen("test.txt", "r");
FILE *fp2 = fopen("test.txt", "r");
if (fp1 == NULL || fp2 == NULL) {
printf("error in opening the text file");
return 1;
}
const int LENGTH = 256;
char line[LENGTH];
int linecount = 0;
while (fgets(line, LENGTH, fp1) != NULL)
{
if (linecount < 10)
linecount = linecount + 1;
else {
fgets(line, LENGTH, fp2);
}
}
if (linecount < 10) {
printf("less than 10 lines in the file\n");
return 1;
}
while (fgets(line, LENGTH, fp2) != NULL)
{
printf("%s", line);
}
fclose(fp1);
fclose(fp2);
return 0;
}
I assume that each line has less than 256 characters, program needs modifications if the length is larger than 256
A better solution is to maintain a [int] count of the number of lines read & an array with size equal to the number of lines to display. Here is the basic algorithm,
PrintLastNLine( int numOfLines )
1) Declare an array --> string arrLines[ numOfLines ];
2) int count = 1;
3) while ( !EOF ) read current line
4) check if count == numOfLines. If true, set count = 1;
5) arrLines[ count -1 ] = current line read from ifstream;
6) count++;
It is important to understand step 4). Array holds only those lines that are to be printed. But we don't know when line Nth from last is reached.
Let's say our file has 50 lines and you have to print last 20 lines. So, line 1 to line 20 has been stored in the array. But EOF is not yet reached & count = 20. So reset the count to 1 & dump the next lines in array again. When ifstream reaches line 21 to line 40,
count = 20 again &
arrLines[0-19] = entries from line 21 to 40.[Note lines 21-30 not needed but lines 31-40 reqd]
Now set count = 1 again.
start reading from line 41 & save in array from count = 1 to 10. [ at 10 EOF is reached]
arrLines[0-9] = line 41 to line 50
arrLines[10-19] = line 31 to line 40
At the end of the loop varialbe count indicates the index in the array from where you can start printing the lines.
int startPrintFrom = count;
for( int printCount = 0; printCount< numOfLines; printCount++ )
{
if( printCount == startPrintFrom )
{
count = 0;
}
cout<<arrLines[ count ]; // dont use [count -1] here bcoz while
// loop above has already incremented count
count++;
}
Actually i can write the rough implementation. You can do all the necessary boundary condition check for getLine etc & conversion from char [] to string etc.
PrintLastNLines( int iNumOfLines, const char *ipFullName )
{
int count = 1;
string arrLines [ iNumOfLines ];
ifstream reader( ipFullName ); // Open the file & do all necessry checks
while( !EOF )
{
char thisLine[500];
reader.getLine(thisLine) // Read line with ifstream function
if( count == iNumOfLines )
{
count = 1;
}
arrLines[ count - 1 ] = thisLine;
count++;
}
int startPrintFrom = count;
for( int printCount = 0; printCount< numOfLines; printCount++ )
{
if( printCount == startPrintFrom )
{
count = 0;
}
cout<<arrLines[ count ]; // dont use [count -1] here bcoz while
// loop above has already incremented count
count++;
}
}
Hercules is almost right, but he is using C++. If using C++, problem is much simpler because you can just push the file pointer position into a stack or whatever.
My idea is similar. To print the last N lines, we need a int[N] buffer. The buffer is used to store the file pointer location (ftell(...)). Remember the problem of "find the 5th item in a linked list in reverse order"? this is the same.
long pos[10];
1. read each char until reach "\r\n" (or just '\r')
save the current position into pos[i];
2. repeat 1, keep the buffer filled with the last 10 "\r\n" positions
(this can be optimized to avoid shifting the whole array by using some tricks.)
3. when reach EOF, fseek to the pos[0] and print out the last 10 lines.
likexx, I agree with your logic. If your file has 1000 lines & you have to print last 10 [or 100] lines then this solution uses less memory, but reads only last N lines twice. Considering the fact You never know the total number of lines in the file beforehand this code will be much slow in the following boundary condition ->
Print last 10 [or 500] lines of a file. So, if your file has exactly only 10 [or 500] lines your logic ends up reading the file TWICE !! File reading operation is expensive.
If we continue on my logic, then the lines will be read only once. It may look obvious that my solution uses more memory since your logic only keep int[] while i keep string [] or char**. But, if we analuse my logic then at ANY time it keep only string[N] or char[N][] memory. As per your logic, at step 3) you will again end up using memory for string[N] or char[N][].
But I think a lil more brainstorming can result a solution which will be a balance between both approaches.
Go backwards from the end till the first 10 '\n' and then start printing forward from there... but, this would assume that the end of line is '\n' and there are 10 lines in the file. If not, we can add boundary and additional check conditions.
- Raghu October 18, 2007