链表的简单介绍

为什么需要线性链表

当然是为了克服顺序表的缺点,在顺序表中,做插入和删除操作时,需要大量的移动元素,导致效率下降。

线性链表的分类

  • 按照链接方式:单链表、循环链表、双链表
  • 按照实现角度:静态链表、动态链表

线性链表的创建和简单遍历

算法思想

创建一个链表,并对链表的数据进行简单的遍历输出。

算法实现

  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. typedef struct Node
  4. {
  5. int data;//数据域
  6. struct Node * pNext;//指针域 ,通过指针域 可以指下一个节点 “整体”,而不是一部分;指针指向的是和他本身数据类型一模一样的数据,从结构体的层面上说,也就是说单个指向整体,(这里这是通俗的说法,实施情况并非是这样的)下面用代码进行说明。
  7. }NODE,*PNODE; //NODE == struct Node;PNODE ==struct Node *
  8. PNODE create_list(void)//对于在链表,确定一个链表我们只需要找到“头指针”的地址就好,然后就可以确认链表,所以我们直接让他返回头指针的地址
  9. {
  10. int len;//存放有效节点的个数
  11. int i;
  12. int val; //用来临时存放用书输入的节点的的值
  13. PNODE pHead = (PNODE)malloc(sizeof(NODE)); //请求系统分配一个NODE大小的空间
  14. if (NULL == pHead)//如果指针指向为空,则动态内存分配失败,因为在一个链表中首节点和尾节点后面都是NULL,没有其他元素
  15. {
  16. printf("分配内存失败,程序终止");
  17. exit(-1);
  18. }
  19. PNODE pTail = pHead;//声明一个尾指针,并进行初始化指向头节点
  20. pTail->data = NULL;//把尾指针的数据域清空,毕竟和是个结点(清空的话更符合指针的的逻辑,但是不清空也没有问题)
  21. printf("请您输入要生成链表节点的个数:len =");
  22. scanf("%d",&len);
  23. for (i=0;i < len;i++)
  24. {
  25. printf("请输入第%d个节点的值",i+1);
  26. scanf("%d",&val);
  27. PNODE pNew = (PNODE)malloc(sizeof(NODE));//创建新节点,使之指针都指向每一个节点(循环了len次)
  28. if(NULL == pNew)//如果指针指向为空,则动态内存分配失败,pNew 的数据类型是PNODE类型,也就是指针类型,指针指向的就是地址,如果地址指向的 //的 地址为空,换句话说,相当于只有头指针,或者是只有尾指针,尾指针应该是不能的,因为一开始的链表是只有一个 //头指针的,所以说,如果pNew指向为空的话,说明,内存并没有进行分配,这个链表仍然是只有一个头节点的空链表。
  29. {
  30. printf("内存分配失败,程序终止运行!\n");
  31. exit(-1);
  32. }
  33. pNew->data = val; //把有效数据存入pNEW
  34. pTail->pNext = pNew; //把pNew 挂在pTail的后面(也就是pTail指针域指向,依次串起来)
  35. pNew->pNext = NULL;//把pNew的指针域清空
  36. pTail = pNew; //在把pNew赋值给pTai,这样就能循环,实现依次连接(而我们想的是只是把第一个节点挂在头节点上,后面的依次进行,即把第二个
  37. //节点挂在第一个节点的指针域上),这个地方也是前面说的,要给pHead 一个“别名的原因”
  38. /*
  39. 如果不是这样的话,代码是这样写的:
  40. pNew->data = val;//一个临时的节点
  41. pHead->pNext = pNew;//把pNew挂到pHead上
  42. pNew->pNext=NULL; //这个临时的节点最末尾是空
  43. 注释掉的这行代码是有问题的,上面注释掉的代码的含义是分别把头节点后面的节点都挂在头节点上,
  44. 导致头节点后面的节点的指针域丢失(不存在指向),而我们想的是只是把第一个节点挂在头节点上,后面的依次进行,即把第二个
  45. 节点挂在第一个节点的指针域上,依次类推,很明显上面所注释掉的代码是实现不了这个功能的,pTail 在这里的做用就相当于一个中转站的作用,类似于两个数交换算法中的那个中间变量的作用,在一个链表中pHead 是头节点,这个在一个链表中是只有一个的,但是如果把这个节点所具备的属性赋值给另外的一个变量(pTail)这样的话,pTail 就相当于另外的一个头指针,然后当然也是可以循环。
  46. */
  47. }
  48. return pHead;//返回头节点的地址
  49. }
  50. void traverse_list(PNODE pHead)//怎样遍历,是不能像以前一样用数组的,以为数组是连续的,这里不连续
  51. {
  52. PNODE p = pHead->pNext;
  53. while (NULL != p)
  54. {
  55. printf("%d ", p->data);
  56. p = p->pNext;
  57. }
  58. printf("\n");
  59. }
  60. int main(void)
  61. {
  62. PNODE pHead = NULL;//等价于 struct Node * pHead = NULL;把首节点的地址赋值给pHead(在一个链表中首节点和尾节点后面都是NULL,没有其他元素)
  63. //PNODE 等价于struct Node *
  64. pHead = create_list();
  65. traverse_list(pHead);
  66. return 0;
  67. }

运行演示

算法小结

这只是一个简单的示例,其中用到的插入节点的算法就是尾插法,下面有具体的算法。

线性链表头插法实现

算法思想

从一个空表开始,每次读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前表的表头结点之后。

算法实现

  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. typedef struct Node
  4. {
  5. int data;
  6. struct Node * pNext;
  7. }NODE,*PNODE;
  8. //遍历
  9. void traverse_list(PNODE pHead)//怎样遍历,是不能像以前一样用数组的,以为数组是连续的,这里不连续
  10. {
  11. PNODE p = pHead->pNext;
  12. while (NULL != p)
  13. {
  14. printf("%d ", p->data);
  15. p = p->pNext;
  16. }
  17. printf("\n");
  18. }
  19. PNODE create_list(void)
  20. {
  21. PNODE pHead = (PNODE)malloc(sizeof(NODE));
  22. pHead->pNext = NULL;
  23. printf("请输入要生成的链表的长度\n");
  24. int n;
  25. int val;
  26. scanf("%d",&n);
  27. for (int i = n;i > 0;i--)
  28. {
  29. printf("请输入的第%d个数据",i);
  30. PNODE p = (PNODE)malloc(sizeof(NODE));//建立新的结点p
  31. if(NULL == p)
  32. {
  33. printf("内存分配失败,程序终止运行!\n");
  34. exit(-1);
  35. }
  36. scanf("%d",&val);
  37. p->data = val;
  38. p->pNext = pHead->pNext;//将p结点插入到表头,这里把头节点的指针赋给了p结点
  39. //此时,可以理解为已经把p节点和头节点连起来了,头指针指向,也就变成了
  40. //p节点的指针指向了(此时的p节点相当于首节点了)
  41. pHead->pNext = p;
  42. }
  43. return pHead;
  44. }
  45. int main(void)
  46. {
  47. PNODE pHead = NULL;
  48. pHead = create_list();
  49. traverse_list(pHead);
  50. return 0;
  51. }

运行演示

算法小结

采用头插法得到的单链表的逻辑顺序与输入元素顺序相反,所以也称头插法为逆序建表法。为什么是逆序的呢,因为在开始建表的时候,所谓头插法,就是新建一个结点,然后链接在头节点的后面,也就是说,最晚插入的结点,离头节点的距离也就是越近!这个算法的关键是 p->data = val;p->pNext = pHead->pNext; pHead->pNext = p;。用图来表示的话可能更加清晰一些。

线性链表尾插法实现

算法思想

头插法建立链表虽然算法简单,但生成的链表中节点的次序和输入顺序相反,如果希望二者的顺序一致,可以采用尾插法,为此需要增加一个尾指针r,使之指向单链表的表的表尾。

算法实现

  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. typedef struct Node
  4. {
  5. int data;
  6. struct Node * pNext;
  7. } NODE,*PNODE;
  8. PNODE create_list(void)
  9. {
  10. PNODE pHead = (PNODE)malloc(sizeof(NODE));
  11. pHead->pNext = NULL;
  12. printf("请输入要生成的链表的长度:\n");
  13. int n;
  14. int val;
  15. PNODE r = pHead;//r 指针动态指向链表的当前表尾,以便于做尾插入,其初始值指向头节点,
  16. //这里可以总结出一个很重要的知识点,如果都是指针类型的数据,“=”可以以理解为指向。
  17. scanf("%d",&n);
  18. for(int i = 0;i < n;i++)
  19. {
  20. printf("请输入的第%d个数据",i+1);
  21. PNODE p = (PNODE)malloc(sizeof(NODE));
  22. if(NULL == p)
  23. {
  24. printf("内存分配失败,程序终止运行!");
  25. exit(-1);
  26. }
  27. scanf("%d",&val);
  28. p->data = val; //给新节点p的数据域赋值
  29. r->pNext = p;//因为一开始尾指针r是指向头节点的, 这里又是尾指针指向s
  30. // 所以,节点p已经链接在了头节点的后面了
  31. p->pNext = NULL; //把新节点的指针域清空 ,先清空可以保证最后一个的节点的指针域为空
  32. r = p; // r始终指向单链表的表尾,这样就实现了一个接一个的插入
  33. }
  34. return pHead;
  35. }
  36. //遍历
  37. void traverse_list(PNODE pHead)//怎样遍历,是不能像以前一样用数组的,以为数组是连续的,这里不连续
  38. {
  39. PNODE p = pHead->pNext;
  40. while (NULL != p)
  41. {
  42. printf("%d ", p->data);
  43. p = p->pNext;
  44. }
  45. printf("\n");
  46. }
  47. //删除
  48. void DelList(PNODE pHead,int i,int * e)
  49. //在带头节点的单链表L中删除第i个元素,并将删除的元素保存到变量 *e 中
  50. {
  51. NODE * pre;
  52. NODE * r;
  53. int k = 0;
  54. pre = pHead;
  55. while (pre->pNext!=NULL && k<i-1)
  56. //寻找被删除结点i的前驱节点i-1,使p指向它
  57. {
  58. pre = pre->pNext;
  59. k = k+1;
  60. }
  61. if(pre->pNext == NULL)
  62. {
  63. printf("删除位置i不合理!");
  64. exit(-1);
  65. }
  66. r = pre->pNext;
  67. pre->pNext = r->pNext;//修改指针,删除结点
  68. *e = r->data;
  69. printf("您要删除的结点%d已经被删除!",*e);
  70. free(r);//注意顺序,是最后才把rfree掉!
  71. }
  72. int main(void)
  73. {
  74. int val;
  75. PNODE pHead = NULL;
  76. pHead = create_list();
  77. traverse_list(pHead);
  78. DelList(pHead,2,&val);
  79. traverse_list(pHead);
  80. return 0;
  81. }

运行演示

算法小结

通过尾插法的学习,进一步加深了对链表的理解,“=”可以理解为赋值号,也可以理解为“指向”,两者灵活运用,可以更好的理解链表中的相关内容。

还有,这个尾差法其实就是这篇文章中的一开始那个小例子中使用的方法。两者可以比较学习。

查找第i个节点(找到后返回此个节点的指针)

按序号查找

算法思想

在单链表中,由于每个结点 的存储位置都放在其前一个节点的next域中,所以即使知道被访问的节点的序号,也不能想顺序表中那样直接按照序号访问一维数组中的相应元素,实现随机存取,而只能从链表的头指针触发,顺链域next,逐个结点往下搜索,直到搜索到第i个结点为止。

要查找带头节点的单链表中第i个节点,则需要从**单链表的头指针L出发,从头节点(pHead->next)开始顺着链表扫描,用指针p指向当前扫面到的节点,初始值指向头节点,用j做计数器,累计当前扫描过的节点数(初始值为0).当i==j时,指针p所指向的节点就是要找的节点。

代码实现

  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. typedef struct Node
  4. {
  5. int data;
  6. struct Node * pNext;
  7. } NODE,*PNODE;
  8. PNODE create_list(void)
  9. {
  10. PNODE pHead = (PNODE)malloc(sizeof(NODE));
  11. pHead->pNext = NULL;
  12. printf("请输入要生成的链表的长度:\n");
  13. int n;
  14. int val;
  15. PNODE r = pHead;
  16. scanf("%d",&n);
  17. for(int i = 0;i < n;i++)
  18. {
  19. printf("请输入的第%d个数据",i+1);
  20. PNODE p = (PNODE)malloc(sizeof(NODE));
  21. if(NULL == p)
  22. {
  23. printf("内存分配失败,程序终止运行!");
  24. exit(-1);
  25. }
  26. scanf("%d",&val);
  27. p->data = val;
  28. r->pNext = p;
  29. p->pNext = NULL;
  30. r = p;
  31. }
  32. return pHead;
  33. }
  34. //查找第i个节点
  35. NODE * getID(PNODE pHead,int i)//找到后返还该节点的地址,只需要需要头节点和要找的节点的序号
  36. {
  37. int j; //计数,扫描的次数
  38. NODE * p;
  39. if(i<=0)
  40. return 0;
  41. p = pHead;
  42. j = 0;
  43. while ((p->pNext!=NULL)&&(j<i))
  44. {
  45. p = p->pNext;
  46. j++;
  47. }
  48. if(i==j)//找到了第i个节点
  49. return p;
  50. else
  51. return 0;
  52. }
  53. //遍历
  54. void traverse_list(PNODE pHead)//怎样遍历,是不能像以前一样用数组的,以为数组是连续的,这里不连续
  55. {
  56. PNODE p = pHead->pNext;
  57. while (NULL != p)
  58. {
  59. printf("%d ", p->data);
  60. p = p->pNext;
  61. }
  62. printf("\n");
  63. }
  64. int main(void)
  65. {
  66. PNODE pHead = NULL;
  67. int n;
  68. NODE * flag;
  69. pHead = create_list();
  70. traverse_list(pHead);
  71. printf("请输入你要查找的结点的序列:");
  72. scanf("%d",&n);
  73. flag = getID(pHead,n);
  74. if(flag != 0)
  75. printf("找到了!");
  76. else
  77. printf("没找到!") ;
  78. return 0;
  79. }

运行演示

按值查找

算法思想

按值查找是指在单链表中查找是否有值等于val的结点,在查找的过程中从单链表的的头指针指向的头节点开始出发,顺着链逐个将结点的值和给定的val做比较,返回结果。

代码实现

  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. #include <cstdlib> //为了总是出现null未定义的错误提示
  4. typedef struct Node
  5. {
  6. int data;
  7. struct Node * pNext;
  8. } NODE,*PNODE;
  9. PNODE create_list(void)
  10. {
  11. PNODE pHead = (PNODE)malloc(sizeof(NODE));
  12. pHead->pNext = NULL;
  13. printf("请输入要生成的链表的长度:\n");
  14. int n;
  15. int val;
  16. PNODE r = pHead;
  17. scanf("%d",&n);
  18. for(int i = 0;i < n;i++)
  19. {
  20. printf("请输入的第%d个数据",i+1);
  21. PNODE p = (PNODE)malloc(sizeof(NODE));
  22. if(NULL == p)
  23. {
  24. printf("内存分配失败,程序终止运行!");
  25. exit(-1);
  26. }
  27. scanf("%d",&val);
  28. p->data = val;
  29. r->pNext = p;
  30. p->pNext = NULL;
  31. r = p;
  32. }
  33. return pHead;
  34. }
  35. //查找按照数值
  36. NODE * getKey(PNODE pHead,int key)
  37. {
  38. NODE * p;
  39. p = pHead->pNext;
  40. while(p!=NULL)
  41. {
  42. if(p->data != key)
  43. {
  44. p = p->pNext;//这个地方要处理一下,要不然找不到的话就指向了系统的的别的地方了emmm
  45. if(p->pNext == NULL)
  46. {
  47. printf("对不起,没要找到你要查询的节点的数据!");
  48. return p;//这样的话,如果找不到的话就可以退出循环了,而不是一直去指。。。。造成指向了系统内存emmm
  49. }
  50. }
  51. else
  52. break;
  53. }
  54. printf("您找的%d找到了!",p->data) ;
  55. return p;
  56. }
  57. //遍历
  58. void traverse_list(PNODE pHead)//怎样遍历,是不能像以前一样用数组的,以为数组是连续的,这里不连续
  59. {
  60. PNODE p = pHead->pNext;
  61. while (NULL != p)
  62. {
  63. printf("%d ", p->data);
  64. p = p->pNext;
  65. }
  66. printf("\n");
  67. }
  68. int main(void)
  69. {
  70. PNODE pHead = NULL;
  71. int val;
  72. pHead = create_list();
  73. traverse_list(pHead);
  74. printf("请输入你要查找的结点的值:");
  75. scanf("%d",&val);
  76. getKey(pHead,val);
  77. return 0;
  78. }

运行演示

算法小结

两个算法都是差不多的,第一个按序号查找,定义了一个计数变量j,它有两个作用,第一个作用是记录节点的序号,第二个作用是限制指针指向的范围,防止出现指针指向别的地方。第二个按值查找,当然也可以用相同的方法来限制范围,防止指针指向别的位置。或者和上面写的那样,加一个判断,如果到了表尾,为空了,就退出循环。

求链表的长度

算法思想

采用“数”结点的东方法求出带头结点单链表的长度。即从“头”开始“数”(p=L->next),用指针p依次指向各个节点。并设计计数器j,一直疏导最后一个节点(p->next == NUll),从而得到单链表的长度。

算法实现

  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. #include <cstdlib> //为了总是出现null未定义的错误提示
  4. typedef struct Node
  5. {
  6. int data;
  7. struct Node * pNext;
  8. } NODE,*PNODE;
  9. PNODE create_list(void)
  10. {
  11. PNODE pHead = (PNODE)malloc(sizeof(NODE));
  12. pHead->pNext = NULL;
  13. printf("请输入要生成的链表的节点(输入0结束):\n");
  14. int val=1;//赋一个初始值,防止 因为垃圾值而报错,下面都会被scanf函数给覆盖掉
  15. PNODE r = pHead;
  16. while(val != 0)
  17. {
  18. PNODE p = (PNODE)malloc(sizeof(NODE));
  19. if(NULL == p)
  20. {
  21. printf("内存分配失败,程序终止运行!");
  22. exit(-1);
  23. }
  24. scanf("%d",&val);
  25. p->data = val;
  26. r->pNext = p;
  27. p->pNext = NULL;
  28. r = p;
  29. }
  30. return pHead;
  31. }
  32. //计算链表的长度
  33. int ListLength(PNODE pHead)
  34. {
  35. NODE * p;
  36. int j;//计数
  37. p = pHead->pNext;
  38. j = 0;
  39. while(p!=NULL)
  40. {
  41. p = p->pNext;
  42. j++;
  43. }
  44. return j;
  45. }
  46. int main(void)
  47. {
  48. PNODE pHead = NULL;
  49. pHead = create_list();
  50. int len = ListLength(pHead);
  51. printf("%d",len);
  52. return 0;
  53. }

运行演示

算法小结

在顺序表中,线性表的长度是它的属性,数组定义时就已经确定,在单链表中,整个链表由“头指针”来表示,单链表的长度在头到尾遍历的过程中统计计数,得到长度值未显示保存。

求单链表中的最大值以及实现就地址逆置链表

算法思想(求单链表的最大值)

通过两个指针就可以很简单实现这个问题,值得注意的是,要主要模拟比较的过程,通过指针指向的两个节点的数据域进行比较,把数据域大的节点的地址返回,如果找不到一直找。

算法实现

  1. # include <stdio.h>
  2. # include <stdlib.h>
  3. typedef struct Node
  4. {
  5. int data;
  6. struct Node * pNext;
  7. } NODE,*PNODE;
  8. PNODE create_list(void)
  9. {
  10. PNODE pHead = (PNODE)malloc(sizeof(NODE));
  11. pHead->pNext = NULL;
  12. printf("请输入要生成的链表的长度:\n");
  13. int n;
  14. int val;
  15. PNODE r = pHead;
  16. scanf("%d",&n);
  17. for(int i = 0;i < n;i++)
  18. {
  19. printf("请输入的第%d个数据",i+1);
  20. PNODE p = (PNODE)malloc(sizeof(NODE));
  21. if(NULL == p)
  22. {
  23. printf("内存分配失败,程序终止运行!");
  24. exit(-1);
  25. }
  26. scanf("%d",&val);
  27. p->data = val;
  28. r->pNext = p;
  29. p->pNext = NULL;
  30. r = p;
  31. }
  32. return pHead;
  33. }
  34. //查找单链表中的最大值
  35. NODE * SearchMAx(PNODE pHead)
  36. {
  37. NODE * p1;//定义两个指针,依次比较两次的数据域大小
  38. NODE * p2;
  39. p1 = pHead->pNext;
  40. p2 = p1->pNext;
  41. while(p2 != NULL)
  42. {
  43. if(p2->data > p1->data) //注意这里和上面的赋值的顺序
  44. {
  45. p1 = p2;//把p1定义为最大结点的指针
  46. p2 = p2->pNext;//继续走链表
  47. }
  48. else
  49. {
  50. p2 = p2->pNext; //如果一直没有找到比p1大的数据,继续找
  51. }
  52. }
  53. return p1;//把最大的节点的地址返回
  54. }
  55. int main(void)
  56. {
  57. PNODE pHead = NULL;
  58. NODE * p;
  59. pHead = create_list();
  60. p = SearchMAx(pHead);
  61. printf("链表中的最大值为%d",p->data);
  62. return 0;
  63. }

运行演示

算法思想(就地址逆置换)

算法思想:逆置链表初始为空,表中节点从原链表中依次“删除”,再逐个插入逆置链表的表头(即“头插”到逆置链表中),使它成为逆置链表的“新”的第一个结点,如此循环,直至原链表为空。利用头插法。

算法实现

  1. void converse(LinkList *head)
  2. {
  3. LinkList *p,*q;
  4. p=head->next;
  5. head->next=NULL;
  6. while(p)
  7. {
  8. /*向后挪动一个位置*/
  9. q=p;
  10. p=p->next;
  11. /*头插*/
  12. q->next=head->next;
  13. head->next=q;
  14. }
  15. }

参考文献

  • 数据结构-用C语言描述(第二版)[耿国华]
  • 数据结构(C语言版)[严蔚敏,吴伟民]

数据结构-线性表的链式存储相关算法(C语言实现)的更多相关文章

  1. C++线性表的链式存储结构

    C++实现线性表的链式存储结构: 为了解决顺序存储不足:用线性表另外一种结构-链式存储.在顺序存储结构(数组描述)中,元素的地址是由数学公式决定的,而在链式储存结构中,元素的地址是随机分布的,每个元素 ...

  2. C++编程练习(2)----“实现简单的线性表的链式存储结构“

    单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素. 对于查找操作,单链表的时间复杂度为O(n). 对于插入和删除操作,单链表在确定位置后,插入和删除时间仅为O(1). 单链表不需要分配存储 ...

  3. C 线性表的链式存储实现及插入、删除等操作示例

    一.链式存储的优势 线性表的存储可以通过顺序存储或链式存储实现,其中顺序存储基于数组实现(见本人上一篇博客),在进行插入删除等操作时,需对表内某一部分元素逐个移动,效率较低.而链式结构不依赖于地址连续 ...

  4. 线性表 顺序存储 链式存储 ---java实现

    首先抽象出一个线性表抽象类(包括主要的增删操作) public abstract class MyAbstractList<E> { public abstract void add(E ...

  5. 线性表的链式存储——C语言实现

    SeqList.h #ifndef _WBM_LIST_H_ #define _WBM_LIST_H_ typedef void List; typedef void ListNode; //创建并且 ...

  6. typedef struct LNode命名结构指针(线性表的链式存储)

    一.typedef 关键字 1. 简介: typedef工具是一个高级数据特性,利用typedef可以为某一些类型自定义名称. 2. 工作原理: 例如我们定义链表的存储结构时,需要定义结点的存储数据元 ...

  7. 线性表的链式存储C语言版

    #include <stdio.h> #include <malloc.h> #define N 10 typedef struct Node { int data; stru ...

  8. 线性表的链式存储结构的实现及其应用(C/C++实现)

    存档----------- #include <iostream.h> typedef char ElemType; #include "LinkList.h" voi ...

  9. javascript实现数据结构:线性表--线性链表(链式存储结构)

    上一节中, 线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任一元素,它的存储位置可用一个简单,直观的公式来表示.然后,另一方面来看,这个特点也造成这种存储 ...

随机推荐

  1. IDEA 使用tomcat7-maven-plugin

    使用了这个插件就不需要配置tomcat了,直接用maven去run就行 配置方法:pom里添加:(之所以用tomcat7是因为如果直接用依赖下载很难下载到tomcat8-maven-plugin,详情 ...

  2. LeetCode之Easy篇 ——(7)Reverse Integer

    7.Reverse Integer Given a 32-bit signed integer, reverse digits of an integer. Example 1: Input: Out ...

  3. ### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to chec

    数据库连接超时,是数据库连接时的相关配置写错,例如:数据库密码,驱动等问题

  4. RouterPassView——路由器密码查看工具

    大多数现代路由器都可以让您备份一个文件路由器的配置文件,然后在需要的时候从文件中恢复配置.路由器的备份文件通常包含了像您的ISP的用户名重要数据/密码,路由器的登录密码,无线网络的KEY. 如果你忘记 ...

  5. mysql, sql sever , oracle

    一.sqlserver优点:易用性.适合分布式组织的可伸缩性.用于决策支持的数据仓库功能.与许多其他服务器软件紧密关联的集成性.良好的性价比等:为数据管理与分析带来了灵活性,允许单位在快速变化的环境中 ...

  6. SpringtMVC运行流程:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的(源码理解)

    在平时开发SpringtMVC程序时,在Controller的方法上,通常会传入如Map.HttpServletRequest类型的参数,并且可以方便地向里面添加数据.同时,在Jsp中还可以直接使用r ...

  7. bat脚本:Java一键编译(Javac java)

    bat脚本:Java一键编译(Javac java) D:    是指D盘 javat是要编译的.java文件所在的文件夹 也就是D:\javat bat代码: :start COLOR 0A cls ...

  8. Pick up lines搭讪

    1.In a bar Do you come here often? I've never seen you here before. What do you think of this bar? A ...

  9. 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址;

    package com.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.htt ...

  10. java 打印近似圆

    只要给定不同半径,圆的大小就会随之发生改变近似圆如图 设半径为r,圆心为(r,r). 由勾股定理 易得y = r -√(2*r*x-x*x) 此处注意x+=2.因为打印窗口上一行2个字节的宽度与一列的 ...