• 看到哪里排序到哪里的ListView


        这个做了两天的小demo(下载)主要是为了解决如何在ListView上排序大量数据的问题。

        这个Demo窗口上的ListView有一百万个项目,点了“Sort”之后就会开始排序。但这个排序跟以往的不同,你看到哪里它排到哪里,但这个排序不仅仅是在窗口内部排,而是你看到的内容都是正确的。

        举个例子,你在浏览1000-1020条的时候,我会开始排序(当然有一点点延迟,不过不会卡窗口),然后确保1000-1020一定是【全局中的】第1000小到第1020小的,就如同全部排过序一样。而且还有一个副作用,就是小于1000的全部比1000小,大于1020的全部比1020大(这可以让你继续浏览的时候排序迅速收敛,而且这听起来应该很熟悉,嘿嘿)。

        很明显,算法是一个线程+消息队列的快速排序变形。

        欢迎下载并试用。

    ------------------------------------------------------------------------------------------

    下面是代码(如果不想下载可以直接看,不过强烈建议亲身体验)

    ------------------------------------------------------------------------------------------

      1 using System;
      2 using System.Collections.Generic;
      3 using System.ComponentModel;
      4 using System.Data;
      5 using System.Drawing;
      6 using System.Linq;
      7 using System.Text;
      8 using System.Windows.Forms;
      9 using System.Reflection;
     10 using System.Threading;
     11 
     12 namespace PartialSort
     13 {
     14     public partial class Form1 : Form
     15     {
     16         private DataManager manager = null;
     17         private bool sorted = false;
     18 
     19         public Form1()
     20         {
     21             InitializeComponent();
     22             PropertyInfo prop = listViewData.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
     23             prop.SetValue(listViewData, truenew object[] { });
     24             manager = new DataManager();
     25             listViewData.VirtualListSize = manager.Count;
     26         }
     27 
     28         private void Form1_Load(object sender, EventArgs e)
     29         {
     30         }
     31 
     32         private void listViewData_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
     33         {
     34             if (sorted)
     35             {
     36                 manager.WantToBeSorted(e.ItemIndex);
     37             }
     38             DataItem item = manager[e.ItemIndex];
     39             e.Item = new ListViewItem(new string[] 
     40             { 
     41                 e.ItemIndex.ToString(), 
     42                 item.id.ToString(), 
     43                 item.content.ToString(),
     44                 manager.IsHit(e.ItemIndex) ? "YES" : ""
     45             });
     46         }
     47 
     48         private void button1_Click(object sender, EventArgs e)
     49         {
     50             sorted = true;
     51             timerRefresh.Enabled = true;
     52             listViewData.Refresh();
     53         }
     54 
     55         private void timerRefresh_Tick(object sender, EventArgs e)
     56         {
     57             if (manager.Sorting)
     58             {
     59                 int count = listViewData.Height / listViewData.TopItem.Bounds.Height;
     60                 for (int i = 0; i < count; i++)
     61                 {
     62                     int index = listViewData.TopItem.Index + i;
     63                     if (manager.IsHit(count))
     64                     {
     65                         break;
     66                     }
     67                 }
     68             }
     69             else
     70             {
     71                 timerRefresh.Enabled = false;
     72             }
     73             listViewData.Refresh();
     74         }
     75 
     76         private void Form1_FormClosed(object sender, FormClosedEventArgs e)
     77         {
     78             manager.Close();
     79         }
     80     }
     81 
     82     public struct DataItem
     83     {
     84         public int id;
     85         public double content;
     86     }
     87 
     88     public struct Pair
     89     {
     90         public int first;
     91         public int second;
     92     }
     93 
     94     public class DataManager
     95     {
     96         private DataItem[] items = null;
     97         private int[] indices = null;
     98         private bool[] hits = null;
     99         private List<Pair> ranges = new List<Pair>();
    100 
    101         private List<int> request = new List<int>();
    102         private Thread sorter = null;
    103         private int sorted = 0;
    104 
    105         private int SearchRange(int index)
    106         {
    107             int firstLarger = ranges.Count;
    108             int start = 0;
    109             int end = ranges.Count - 1;
    110             while (start <= end)
    111             {
    112                 int mid = (start + end) / 2;
    113                 Pair p = ranges[mid];
    114                 if (p.second < index)
    115                 {
    116                     start = mid + 1;
    117                 }
    118                 else if (index < p.first)
    119                 {
    120                     end = mid - 1;
    121                     firstLarger = mid;
    122                 }
    123                 else
    124                 {
    125                     return firstLarger;
    126                 }
    127             }
    128             return firstLarger;
    129         }
    130 
    131         private void TryMerge(int firstIndex)
    132         {
    133             if (firstIndex >= 0 && firstIndex < ranges.Count - 1)
    134             {
    135                 Pair p1 = ranges[firstIndex];
    136                 Pair p2 = ranges[firstIndex + 1];
    137                 if (p1.second == p2.first - 1)
    138                 {
    139                     p1.second = p2.second;
    140                     ranges[firstIndex] = p1;
    141                     ranges.RemoveAt(firstIndex + 1);
    142                 }
    143             }
    144         }
    145 
    146         private void InsertSortedIndex(int index, int firstLarger)
    147         {
    148             Pair newPair = new Pair();
    149             newPair.first = index;
    150             newPair.second = index;
    151             ranges.Insert(firstLarger, newPair);
    152             TryMerge(firstLarger);
    153             TryMerge(firstLarger - 1);
    154         }
    155 
    156         private void GetUnsortedRange(int firstLarger, out int start, out int end)
    157         {
    158             start = 0;
    159             end = items.Length - 1;
    160             if (ranges.Count > 0)
    161             {
    162                 if (firstLarger == ranges.Count)
    163                 {
    164                     start = ranges[firstLarger - 1].second + 1;
    165                 }
    166                 else if (firstLarger == 0)
    167                 {
    168                     end = ranges[0].first - 1;
    169                 }
    170                 else
    171                 {
    172                     start = ranges[firstLarger - 1].second + 1;
    173                     end = ranges[firstLarger].first - 1;
    174                 }
    175             }
    176         }
    177 
    178         private int Reorder(int start, int end, int index)
    179         {
    180             int current = start;
    181             int target = end;
    182             int offset = -1;
    183             if (end - index < index - start)
    184             {
    185                 current = end;
    186                 target = start;
    187                 offset = 1;
    188             }
    189             int t = indices[index];
    190             indices[index] = indices[current];
    191             indices[current] = t;
    192 
    193             while (current != target)
    194             {
    195                 int result = items[indices[current]].content.CompareTo(items[indices[target]].content);
    196                 if (result * offset < 0)
    197                 {
    198                     t = indices[current];
    199                     indices[current] = indices[target];
    200                     indices[target] = t;
    201 
    202                     t = current;
    203                     current = target;
    204                     target = t;
    205 
    206                     offset *= -1;
    207                 }
    208                 target += offset;
    209             }
    210             sorted++;
    211             return current;
    212         }
    213 
    214         private void SorterFunction()
    215         {
    216             while (Sorting)
    217             {
    218                 int index = -1;
    219                 lock (request)
    220                 {
    221                     if (request.Count > 0)
    222                     {
    223                         index = request[request.Count - 1];
    224                         request.RemoveAt(request.Count - 1);
    225                         if (hits[index])
    226                         {
    227                             index = -1;
    228                         }
    229                     }
    230                 }
    231                 if (index != -1)
    232                 {
    233                     int firstLarger = SearchRange(index);
    234                     int start = 0;
    235                     int end = 0;
    236                     GetUnsortedRange(firstLarger, out start, out end);
    237                     while (true)
    238                     {
    239                         int result = Reorder(start, end, index);
    240                         InsertSortedIndex(result, firstLarger);
    241                         hits[result] = true;
    242                         if (result < index)
    243                         {
    244                             start = result + 1;
    245                         }
    246                         else if (result > index)
    247                         {
    248                             end = result - 1;
    249                         }
    250                         else
    251                         {
    252                             break;
    253                         }
    254                     }
    255                 }
    256                 Thread.Sleep(1);
    257             }
    258         }
    259 
    260         public DataManager()
    261         {
    262             items = new DataItem[10000000];
    263             indices = new int[items.Length];
    264             hits = new bool[items.Length];
    265             Random random = new Random((int)DateTime.Now.Ticks);
    266             for (int i = 0; i < items.Length; i++)
    267             {
    268                 items[i] = new DataItem();
    269                 items[i].id = i;
    270                 items[i].content = random.NextDouble();
    271                 indices[i] = i;
    272                 hits[i] = false;
    273             }
    274             sorter = new Thread(SorterFunction);
    275             sorter.Start();
    276         }
    277 
    278         public void WantToBeSorted(int index)
    279         {
    280             if (hits[index]) return;
    281             lock (request)
    282             {
    283                 request.Add(index);
    284             }
    285         }
    286 
    287         public int Count
    288         {
    289             get
    290             {
    291                 return items.Length;
    292             }
    293         }
    294 
    295         public DataItem this[int index]
    296         {
    297             get
    298             {
    299                 return items[indices[index]];
    300             }
    301         }
    302 
    303         public bool IsHit(int index)
    304         {
    305             return hits[index];
    306         }
    307 
    308         public void Close()
    309         {
    310             sorter.Abort();
    311         }
    312 
    313         public bool Sorting
    314         {
    315             get
    316             {
    317                 return items.Length > sorted;
    318             }
    319         }
    320     }
    321 }
    322 
  • 相关阅读:
    Webpack打包原理
    Vue——VNode
    Vue——响应式原理
    HTTP2.0——头部压缩
    HTTP2.0
    浏览器打开2个页面会有几个进程?
    计算机网络——TCP如何保证可靠性
    操作系统——进程之间的通信
    前端路由hash与history下
    前端路由hash与history上
  • 原文地址:https://www.cnblogs.com/geniusvczh/p/1626184.html
Copyright © 2020-2023  润新知