Chinaunix

标题: 大链表查找,求解决方法 [打印本页]

作者: lewy7    时间: 2014-08-05 17:44
标题: 大链表查找,求解决方法
求解决方案

结点结构
struct some_s {
int a;
int b;
void *data;
。。。(等等)
};

现在有个单向链表,有100W个结点,如何快速查找 a=18954545941 和 b=0 的结点 。
变量a在所有结点中是唯一的。


如果还有其他更合适的数据结构也可以,不一定要用链表。
作者: cobras    时间: 2014-08-05 17:52
a=18954545941不会被截断吗?编译器没有报警吗?
作者: folklore    时间: 2014-08-05 17:54
  1. std::map<int,int>(a,b);

  2. 或者
  3. struct b{
  4. int a;
  5. int b;
  6. xxx;
  7. }

  8. std::map<int,shared_ptr<struct b>>(a,new b());
复制代码

作者: cobras    时间: 2014-08-05 17:57
如果以a排序存储,采用二分法查找会很快。不过数据结构要改改。如果用数组更快。用链表也行,不过要增加额外存储的信息。
作者: super皮波    时间: 2014-08-05 18:00
回复 1# lewy7
hash表


   
作者: csumck    时间: 2014-08-05 19:32
这必须用map+list实现啊, 网上很多哈希表都是带list功能的
作者: Dannysd    时间: 2014-08-05 19:48
本帖最后由 Dannysd 于 2014-08-05 19:49 编辑

快速排序后,二分查找
链表也可以快速排序,二级指针就够用
作者: yulihua49    时间: 2014-08-07 16:01
本帖最后由 yulihua49 于 2014-08-07 16:05 编辑
lewy7 发表于 2014-08-05 17:44
求解决方案

结点结构

二叉树,
STL的map。。。。。

long long a;

每个节点地址组成数组,排序,二分法。
hash,都可以。

二叉树省事一些。
作者: hanxin83    时间: 2014-08-08 15:24
Boost.MultiIndex....绝对适合你.
作者: starwing83    时间: 2014-08-08 18:25
回复 7# Dannysd


    亲,链表可以二分查找么?
作者: Dannysd    时间: 2014-08-08 23:41
本帖最后由 Dannysd 于 2014-08-08 23:47 编辑

回复 10# starwing83



   当然,如果是用 struct test *next这样的链表应该是不行的,用二级指针不是可以当作二维数组那样访问嘛~  
作者: starwing83    时间: 2014-08-09 00:26
回复 11# Dannysd


    亲,二级指针也得链表node本身在内存里是连续的,即使链表本身的存储是连续的,在排序之后连续的元素也不一定是排序的连续元素了(因为只更改了next指针的值,并没有拷贝移动元素本身——这也是链表排序的优势),因此这时候你用二级指针直接就是作死。

一般的链表,通过malloc/free分配,你用二级指针操作除非是想crash想着急了
作者: fender0107401    时间: 2014-08-09 08:22
如果只有链表,那就没有好讲的了。

如果想提高查询性能,那就一定要有一个辅助的数据结构,或者干脆转化为其他的存储方式,比如hash table。
作者: Dannysd    时间: 2014-08-09 23:06
回复 12# starwing83


    我表达不太清楚,请大神参考一下scandir的实现(其中一个版本),如下
  1. /*
  2. * scandir, alphasort - scan a directory
  3. *
  4. * implementation for systems that do not have it in libc
  5. */

  6. #include "../config.h"

  7. #ifndef        HAVE_SCANDIR

  8. #include <sys/types.h>
  9. #include <dirent.h>
  10. #include <stdlib.h>
  11. #include <stddef.h>
  12. #include <string.h>

  13. /*
  14. * convenience helper function for scandir's |compar()| function:
  15. * sort directory entries using strcoll(3)
  16. */
  17. int
  18. alphasort(const void *_a, const void *_b)
  19. {
  20.     struct dirent **a = (struct dirent **)_a;
  21.     struct dirent **b = (struct dirent **)_b;
  22.     return strcoll((*a)->d_name, (*b)->d_name);
  23. }


  24. #define strverscmp(a,b) strcoll(a,b) /* for now */

  25. /*
  26. * convenience helper function for scandir's |compar()| function:
  27. * sort directory entries using GNU |strverscmp()|
  28. */
  29. int
  30. versionsort(const void *_a, const void *_b)
  31. {
  32.     struct dirent **a = (struct dirent **)_a;
  33.     struct dirent **b = (struct dirent **)_b;
  34.     return strverscmp((*a)->d_name, (*b)->d_name);
  35. }

  36. /*
  37. * The scandir() function reads the directory dirname and builds an
  38. * array of pointers to directory entries using malloc(3).  It returns
  39. * the number of entries in the array.  A pointer to the array of
  40. * directory entries is stored in the location referenced by namelist.
  41. *
  42. * The select parameter is a pointer to a user supplied subroutine
  43. * which is called by scandir() to select which entries are to be
  44. * included in the array.  The select routine is passed a pointer to
  45. * a directory entry and should return a non-zero value if the
  46. * directory entry is to be included in the array.  If select is null,
  47. * then all the directory entries will be included.
  48. *
  49. * The compar parameter is a pointer to a user supplied subroutine
  50. * which is passed to qsort(3) to sort the completed array.  If this
  51. * pointer is null, the array is not sorted.
  52. */
  53. int
  54. scandir(const char *dirname,
  55.         struct dirent ***ret_namelist,
  56.         int (*select)(const struct dirent *),
  57.         int (*compar)(const struct dirent **, const struct dirent **))
  58. {
  59.     int i, len;
  60.     int used, allocated;
  61.     DIR *dir;
  62.     struct dirent *ent, *ent2;
  63.     struct dirent **namelist = NULL;

  64.     if ((dir = opendir(dirname)) == NULL)
  65.         return -1;

  66.     used = 0;
  67.     allocated = 2;
  68.     namelist = malloc(allocated * sizeof(struct dirent *));
  69.     if (!namelist)
  70.         goto error;

  71.     while ((ent = readdir(dir)) != NULL) {

  72.         if (select != NULL && !select(ent))
  73.             continue;

  74.         /* duplicate struct direct for this entry */
  75.         len = offsetof(struct dirent, d_name) + strlen(ent->d_name) + 1;
  76.         if ((ent2 = malloc(len)) == NULL)
  77.             return -1;
  78.        
  79.         if (used >= allocated) {
  80.             allocated *= 2;
  81.             namelist = realloc(namelist, allocated * sizeof(struct dirent *));
  82.             if (!namelist)
  83.                 goto error;
  84.         }
  85.         memcpy(ent2, ent, len);
  86.         namelist[used++] = ent2;
  87.     }
  88.     closedir(dir);

  89.     if (compar)
  90.         qsort(namelist, used, sizeof(struct dirent *),
  91.               (int (*)(const void *, const void *)) compar);

  92.     *ret_namelist = namelist;
  93.     return used;


  94. error:
  95.     if (namelist) {
  96.         for (i = 0; i < used; i++)
  97.             free(namelist[i]);
  98.         free(namelist);
  99.     }
  100.     return -1;
  101. }
  102. #endif


  103. #if        STANDALONE_MAIN
  104. int
  105. main(int argc, char **argv)
  106. {
  107.         struct dirent **namelist;
  108.         int i, n;

  109.         n = scandir("/etc", &namelist, NULL, alphasort);

  110.         for (i = 0; i < n; i++)
  111.                 printf("%s\n", namelist[i]->d_name);
  112. }
  113. #endif
复制代码

作者: action08    时间: 2014-08-10 12:33
回复 3# folklore


    map是红黑树,比left+right二叉树性能要稳定多了
作者: sxcong    时间: 2014-08-13 11:27
linux下经常用的list_entry是最快的。
根据地址直接查到,不管你是千万还是亿万。
libuv里有简单的例子:

#define container_of(ptr, type, member) \
  ((type *) ((char *) (ptr) - offsetof(type, member)))

struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle);

原理就是记住某个结构体里的某个变量的内存地址。自行搜索一下,http://blog.csdn.net/jiatingqiang/article/details/6437496 这里也有。
这也是为什么指针对c/c++如此重要的原因。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2