There are 2 rudimentary ways that I can think of off the top of my head...none of them are optimal though..
1. Use max to find the largest element, then set this element to -Inf. Then use max again to find the 'next'(ie, second) largest element and its position.
This method is definitely only a quick heck, and not suitable for looking for the Nth largest element in case N in large.
2. Sort the matrix, then you will know the value of the second largest element, then use 'find' to get the position of this element.
Hope this helps,
stephanie
Call SORT with two output arguments.
--
Steve Lord
sl...@mathworks.com
Example for m by n matrix:
m=3;n=4;ggg = rand(m,n);
[svals,idx] = sort(ggg(:),'descend'); % sort to vector
svals(2) % second largest value
[II,JJ] = ind2sub([m,n],idx(2)) % position in the matrix
You could also use sort on A(:).
Hope this helps.
Greg
> Can anyone pls tell me how I can find the second (or third) largest element in a
> matrix AND its position.
The algorithms that people gave all ran in -at least- time N (length of the
matrix) times the number of largest elements to be found.
I was interested to discover a couple of weeks ago that there are simple
algorithms that for any fixed number L of largest elements, are able to
execute a -single- pass over the array and using L (or was it L+1 ?)
temporary storage locations, find the L largest values.
Unfortunately in the short time I put into reading the algorithm, I did
not understand how the algorithm worked, so I cannot describe it here.
And I no longer recall where I found the algorithm -- though either as
a reference here or on wikipedia are the two most likely candidates.
Walter Roberson <robe...@hushmail.com> wrote in message <STjCk.14881$Il....@newsfe09.iad>...
if temp is your vector, you can get the second largest element as follows:
[c,i] = max(temp(temp~=max(temp)))
why would you sort it?
this is the whole point of logical addressing in matlab.
if temp is your vector, you can get the second largest element as follows:
% Some Data
temp = [8 -1 0 1 2 -3 -8 0 5 -4]
% Proposed method
[c,i] = max(temp(temp~=max(temp)));
% As a check:
[srt,idx] = sort(temp,'descend');
idx2 = find(srt~=srt(1),1);
secondhighest = srt(idx2);
location = idx(idx2);
% isequal?
[secondhighest==c,location==i]
Have I misunderstood your proposal?
R = temp; % Preserve R.
R(~(R~=max(R))) = NaN;
[c,i] = max(R);
Depends on the matrix sizes. max() is an order(N) operation. sort is something like
order (N*log(N)). With large matrices, two linear passes through the matrix would be
considerably faster than a sort().
Note: in previous postings, someone posted a reference to a linear-time routine
to find the "Q largest" values in a vector; that code would only pass through the
matrix once (but might make up to Q comparisons at each point in order to establish
the proper ordering.)
> Depends on the matrix sizes. max() is an order(N) operation. sort is something like
> order (N*log(N)). With large matrices, two linear passes through the matrix would be
> considerably faster than a sort().
>
> Note: in previous postings, someone posted a reference to a linear-time routine
> to find the "Q largest" values in a vector; that code would only pass through the
> matrix once (but might make up to Q comparisons at each point in order to establish
> the proper ordering.)
True enough, but I was accounting for the copy time in the comparisons I made (apples to apples ---> We start with a vector and end with the vector intact plus the second largest value and its index.)
Nevertheless my timings show you are correct. The relative speed of the approach shown above increases as N gets larger and larger.
N -------------- tsort/tnan
1000--------1.12703739213806
10^4--------1.33
10^5--------1.36
10^6--------1.67
10^7--------2.2
While searching something related to a stable quicksort I bump into this article:
http://en.wikipedia.org/wiki/Selection_algorithm
The interesting part are "Optimised Sorting algorithm" and "Tournament algorithm".
Bruno
Bruno & Walter,
have you seen my KTHVALUE submission on the FEX?
http://www.mathworks.com/matlabcentral/fileexchange/23195
Best,
Jos
Hi Jos,
Now I see it. Thanks.
Bruno
Thanks,
Bruno
/**************************************************************************
* function [res loc] = minkmex(list, k)
* Matlab C-Mex
* Purpose: Same as MINK, i.e.,
* Return in RES the K smallest elements of LIST
* RES is sorted in ascending order [res loc] = mink(...)
* Location of the smallest: RES=LIST(LOC)
* But this MEX works on double, and output RES is unsorted
* Algorithm according to http://en.wikipedia.org/wiki/Selection_algorithm
* Compilation: mex -O -v minkmex.c
* Author Bruno Luong <bruno...@yahoo.com>
* Last update: 06/April/2009
*************************************************************************/
#include "mex.h"
#include "matrix.h"
#define _DEBUG
/* Global variables, used to avoid stacking them during recusive call since
they do not change */
mwSize k;
mwSize *pos;
double *list;
/* Partitioning the list around pivot pivotValue := l[pivotIndex];
* After runing, at exit we obtain:
l[left]...l[index-1] < pivotValue <= l[index] ... l[right]
where l[i] := list[pos[i]] for all i */
mwSize partition(mwSize left, mwSize right, mwSize pivotIndex) {
double pivotValue;
mwSize *pindex, *pi, *pright;
mwSize tmp;
pright=pos+right;
pindex=pos+pivotIndex;
pivotValue = list[tmp = *pindex];
/* Swap pos[pivotIndex] with pos[right] */
*pindex = *pright;
*pright = tmp;
pindex=pos+left;
for (pi=pindex; pi<pright; pi++)
/* Compare with pivotValue */
if (list[*pi] < pivotValue) {
/* if smaller; Swap pos[index] with p[i] */
tmp = *pindex;
*pindex = *pi;
*pi = tmp;
pindex++;
}
/* Swap pos[index] with p[right] */
tmp = *pindex;
*pindex = *pright;
*pright = tmp;
return (pindex-pos); /* Pointer arithmetic */
} /* Partition */
/* Recursive engine (partial quicksort) */
void findFirstK(mwSize left, mwSize right) {
mwSize pivotIndex;
if (right > left) {
pivotIndex = partition(left, right, (left+right+1)/2);
if (pivotIndex > k)
findFirstK(left, pivotIndex-1);
else if (pivotIndex < k)
findFirstK(pivotIndex+1, right);
}
return;
} /* findFirstK */
/* Gateway of minkmex */
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]) {
mwSize l, i;
double *data;
mwSize dims[2];
/* Check arguments */
if (nrhs<2)
mexErrMsgTxt("MINKMEX: Two input arguments required.");
if (!mxIsNumeric(prhs[0]))
mexErrMsgTxt("MINKMEX: First input LIST argument must be numeric.");
if (!mxIsNumeric(prhs[1]))
mexErrMsgTxt("MINKMEX: Second input K must be numeric.");
/* Get the number of elements of the list of subindexes */
if (mxGetM(prhs[0])==1)
l = mxGetN(prhs[0]);
else if (mxGetN(prhs[0])==1)
l = mxGetM(prhs[0]);
else
mexErrMsgTxt("MINKMEX: First input LIST must be a vector.");
if (mxGetClassID(prhs[0]) != mxDOUBLE_CLASS)
mexErrMsgTxt("MINKMEX: First input LIST must be a double.");
/* Get the number of elements of the list of subindexes */
if (mxGetM(prhs[1])!=1 || mxGetN(prhs[1])!=1)
mexErrMsgTxt("MINKMEX: Second input K must be a scalar.");
if (mxGetClassID(prhs[1]) != mxDOUBLE_CLASS)
mexErrMsgTxt("MINKMEX: Second input K must be a double.");
k = (int)(*mxGetPr(prhs[1]));
if (k<0)
mexErrMsgTxt("MINKMEX: K must be non-negative integer.");
/* Get a data pointer */
list = mxGetPr(prhs[0]);
/* Clip k */
if (k>l) k=l;
/* Clean programming */
pos=NULL;
/* Work for non-empty array */
if (l>0) {
/* Vector of index */
pos = mxMalloc(sizeof(mwSize)*l);
if (pos==NULL)
mexErrMsgTxt("Out of memory.");
/* Initialize the array of position (zero-based index) */
for (i=0; i<l; i++) pos[i]=i;
/* Call the recursive engine */
k--; /* because we work on zero-based */
findFirstK(0, l-1);
k++; /* Restore one-based index */
} /* if (l>0) */
/* Create the Matrix result (first output) */
dims[0] = 1; dims[1] = k;
plhs[0] = mxCreateNumericArray(2, dims, mxDOUBLE_CLASS, mxREAL);
if (plhs[0] == NULL)
mexErrMsgTxt("Out of memory.");
data = mxGetPr(plhs[0]);
for (i=0; i<k; i++) data[i]=list[pos[i]];
/* Create the Matrix position (second output) */
if (nlhs>=2)
{
dims[0] = 1; dims[1] = k;
plhs[1] = mxCreateNumericArray(2, dims, mxDOUBLE_CLASS, mxREAL);
if (plhs[1] == NULL)
mexErrMsgTxt("Out of memory.");
data = mxGetPr(plhs[1]);
for (i=0; i<k; i++) data[i]=(double)(pos[i]+1); /* one-based */
}
/* Free the array of position */
if (pos) mxFree(pos);
pos = NULL; /* clean programming */
return;
} /* Gateway of minkmex.c */
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [res loc] = mink(list, k)
% function res = mink(list, k)
%
% Return in RES the K smallest elements of LIST
% RES is sorted in ascending order
% [res loc] = mink(...)
% Location of the smallest: RES=LIST(LOC)
%
% Author Bruno Luong <bruno...@yahoo.com>
% Last update: 06/April/2009
clist=class(list);
% Mex file requires double
if ~strcmpi(clist,'double')
list=double(list);
end
k=double(k);
[res loc] = minkmex(list(:),k);
[res is] = sort(res);
loc = loc(is);
% Cast to original class
if ~strcmpi(clist,'double')
res=feval(clist,res);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Test on command line
clear
k=10;
n=1e6;
ntest=50;
tmink=zeros(1,ntest);
tsort=zeros(1,ntest);
for i=1:ntest
list=rand(1,n);
tic
m=mink(list,k);
tmink(i)=toc;
tic
s=sort(list);
s=s(1:k);
tsort(i)=toc;
if ~isequal(m,s)
keyboard;
end
end
disp('mink')
disp(median(tmink))
disp('sort:')
disp(median(tsort))
[res,loc] = mink(A,N)
for vector A of length N, the output should be the same as:
[sres,sloc] = sort(A).
But this is not the case for, ex:.
A = randperm(20) - randperm(20);
....
....
[all(loc==sloc) all(res == sres)]
ans =
0 1
Again, it is not a necessity, but for consistency it might be nice!
Thanks. You got it, I will take into account your remark. I'll have to process this case apart. Because the partial quicksort above is not a "stable" ordering algorithm, and I can't see right now how can modify it to become stable one.
Best,
Bruno
Take a look at the command MINK and MAXK, both having (almost) linear complexity and return the position as well.
Bruno