Find closest number in a list

1,Problem

There are two ordered list, the list a and the list b, such as:

a=>[1,14,20,36]

b=>[2,7,11,25,32,39]

the result that I want to get is:

result=>[(2,1),(7,null),(11,14),(25,null),(32,null),(39,36)]

Put it into word: find the closest number(which delta between counterpart  is less than 5) in list a for each item in list b.

 

First of all, I decide to divide the problem to:

1,find closest number for each item in a, since a is less elements than b.

2,compose a result into a list. if no proper value be found, put it to null.

 

Because a&b are ordered list, so binary search is fast way to find out corresponding closest value. The complexity of binary search for a ordered list is O(log(N)).Each of item in list a have O(N), so the total complexity is O(N*log(N))。

 

2,Code

How to use the code:

static void Main(string[] args)
{
    int[] arrTime = { 1, 3, 5, 7, 8, 9, 10, 12, 15, 18, 25 };
    int[] arrAlign = { 3, 6, 11, 15, 22 };

    FindClosestNumber finder = new FindClosestNumber(3);

    var lst = finder.FindClosestAlignment(arrTime, arrAlign);

    foreach (var item in lst)
    {
        Console.WriteLine("{0}\t\t{1}", item.Time, item.Alignment);
    }

    Console.ReadKey();

}

 

There is the code:

public class Pair
    {
        public Pair(int? time, int? alignment)
        {
            Time = time;
            Alignment = alignment;
        }
        public int? Time { set; get; }
        public int? Alignment { set; get; }
    }

public class FindClosestNumber
    {

        public int Threshold { get; set; }

        public FindClosestNumber()
        {
            this.Threshold = 50;

        }
        public FindClosestNumber(int threshold)
        {
            this.Threshold = threshold;
        }


        public  List<Pair> FindClosestAlignment(int[] arrTime, int[] arrAlignment)
        {
            List<Pair> list = FindClosestTime(arrTime, arrAlignment);

            List<Pair> reslut = new List<Pair>();
            for (int i = 0; i < arrTime.Length; i++)
            {
                Pair pair = new Pair(arrTime[i], null);
                foreach (var p in list)
                {
                    if (pair.Time == p.Time)
                        pair.Alignment = p.Alignment;
                }
                reslut.Add(pair);
            }

            return reslut;
        }

        private  List<Pair> FindClosestTime(int[] arrTime, int[] arrAlignment)
        {
            List<Pair> list = new List<Pair>();

            for (int i = 0; i < arrAlignment.Length; i++)
            {
                int el = arrAlignment[i];
                int index = FindClosestIndexInOrderList(el, arrTime, this.Threshold);
                if (index == -1)
                {
                    list.Add(new Pair(null, el));
                }
                else
                {
                    list.Add(new Pair(arrTime[index], el));
                }
            }

            return list;

        }

        private  int FindClosestIndexInOrderList(int val, int[] arr, int threshold)
        {
            int index = Array.BinarySearch(arr, val);
            if (index >= 0)
            {//found
                return index;
            }
            else
            {
                //bitwise complement for index
                int compl = (~index);
                if (compl == arr.Length)
                {//val is biggest value in the arr

                    if (Math.Abs(arr[arr.Length - 1] - val) > threshold)
                        return -1;
                    else
                        return (arr.Length - 1);
                }
                else if (compl == 0)
                {//val is smallest value in the arr
                    if (Math.Abs(arr[0] - val) > threshold)
                        return -1;
                    else
                        return 0;
                }
                else
                {
                    int preIndex = compl - 1;

                    int deltaToPrevious = Math.Abs(arr[preIndex] - val);
                    int deltaToCurrent = Math.Abs(arr[compl] - val);

                    if (deltaToPrevious > threshold)
                        return -1;
                    if (deltaToCurrent > threshold)
                        return -1;

                    return deltaToPrevious <= deltaToCurrent ? preIndex : compl;
                }
            }
        }
    }
posted @ 2012-03-13 22:04  Jerry Chou  阅读(466)  评论(0编辑  收藏  举报