public static IEnumerable <SortNodePair <T> > PairOff <T>(IEnumerable <T> items, IComparer <T> comparer) { List <SortNodePair <T> > pairs = new List <SortNodePair <T> >(items.Count() / 2); SortNode <T> previousNode = null; foreach (T currentItem in items) { if (previousNode == null) { previousNode = new SortNode <T>(currentItem); } else { SortNode <T> currentNode = new SortNode <T>(currentItem); int comparison = comparer.Compare(previousNode.Item, currentItem); if (comparison >= 0) { //previousNode.NumLowerItems = currentNode.NumHigherItems = 1; pairs.Add(new SortNodePair <T>(currentNode, previousNode)); } else { //previousNode.NumHigherItems = currentNode.NumLowerItems = 1; pairs.Add(new SortNodePair <T>(previousNode, currentNode)); } previousNode = null; } // Note that if there is an odd number of items then we don't use the last one } return(pairs); }
public static SortNodePair <T> EstimateMedian <T>(IEnumerable <T> items, IComparer <T> comparer) { // split into sets of two points IEnumerable <SortNodePair <T> > currentPairs = PairOff(items, comparer); List <SortNodePair <T> > nextPairs = new List <SortNodePair <T> >(currentPairs.Count() / 2); // find some pretty good bounds on the median while (currentPairs.Count() > 1) { SortNodePair <T> previousPair = null; foreach (SortNodePair <T> currentPair in currentPairs) { if (previousPair == null) { previousPair = currentPair; } else { // combine currentPair with previousPair, make a new pair, and add it to nextPairs SortNode <T> lowestItem, middleItem1, middleItem2, highestItem; // find the highest and lowest nodes if (comparer.Compare(previousPair.LowerItem.Item, currentPair.LowerItem.Item) < 0) { lowestItem = previousPair.LowerItem; middleItem1 = currentPair.LowerItem; } else { lowestItem = currentPair.LowerItem; middleItem1 = previousPair.LowerItem; } if (comparer.Compare(previousPair.UpperItem.Item, currentPair.UpperItem.Item) < 0) { middleItem2 = previousPair.UpperItem; highestItem = currentPair.UpperItem; } else { middleItem2 = currentPair.UpperItem; highestItem = previousPair.UpperItem; } // make sure middleItem1 < middleItem2 if (comparer.Compare(middleItem1.Item, middleItem2.Item) > 0) { SortNode <T> temp = middleItem2; middleItem2 = middleItem1; middleItem1 = temp; } // make an updated low-middle node SortNode <T> new_lowMiddle = new SortNode <T>(middleItem1.Item); new_lowMiddle.NumEqualItems = middleItem1.NumEqualItems; new_lowMiddle.NumLowerItems = lowestItem.NumLowerItems + middleItem1.NumLowerItems; if (comparer.Compare(lowestItem.Item, new_lowMiddle.Item) < 0) { new_lowMiddle.NumLowerItems += lowestItem.NumEqualItems; } else { new_lowMiddle.NumEqualItems += lowestItem.NumEqualItems; } new_lowMiddle.NumHigherItems = middleItem1.NumHigherItems; // don't need to mark the higher items that new_highMiddle knows about // make an updated high-middle node SortNode <T> new_highMiddle = new SortNode <T>(middleItem2.Item); new_highMiddle.NumEqualItems = middleItem2.NumEqualItems; new_highMiddle.NumLowerItems = middleItem2.NumLowerItems; // don't need to mark the lower items that new_lowerMiddle knows about new_highMiddle.NumHigherItems = middleItem2.NumHigherItems + highestItem.NumHigherItems; if (comparer.Compare(new_highMiddle.Item, highestItem.Item) < 0) { new_highMiddle.NumHigherItems += highestItem.NumEqualItems; } else { new_highMiddle.NumEqualItems += highestItem.NumEqualItems; } nextPairs.Add(new SortNodePair <T>(new_lowMiddle, new_highMiddle)); previousPair = null; } } // If a pair remains, we ignore it //if (previousPair != null) // nextPairs.AddFirst(previousPair); currentPairs = nextPairs; nextPairs = new List <SortNodePair <T> >(currentPairs.Count() / 2); } return(currentPairs.First()); }
public SortNodePair(SortNode <T> lowerItem, SortNode <T> upperItem) { this.LowerItem = lowerItem; this.UpperItem = upperItem; }