1. 二维数组的内存地址是怎么样的?写出寻址公式?
  2. a[] = new int[10]; ==> loc = init_loc(初始内存地址)+index(数组的下标)*size(数据的长度)
  3. 二维=>转化一维
  4. 1 2 3
  5. 4 5 6 => 1 2 3 4 5 6 => 4的下标在二维里面是 1 0 =>在一维里面是第3个。=> i*n(一维的长度)+j(在列 )=>1*3+0=3
  6. a[i][j]: (i<n,j<m)
  7. loc=init_loc+(i*n+j)*size
  1. 链表的定义
  2. 链表通过指针将一组零散的内存块串联在一起。其中,我们把内存块称为链表的“结点”。为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点的地址。画图演示:
  3. 2.特点
  4. (1)不需要连续的内存空间。
  5. (2)有指针引用
  6. (3)三种最常见的链表结构:单链表、双向链表和循环链表
  1. 图形:
  2. 从单链表图中,可以发现,有两个结点是比较特殊的,它们分别是第一个结点和最后一个结点。我们一般把第一个结点叫作头结点,把最后一个结点叫作尾结点。
  3. 其中,头结点用来记录链表的基地址。有了它,我们就可以遍历得到整条链表。而尾结点特殊的地方是:指针不是指向下一个结点,而是指向一个空地址NULL,表示这是链表上最后一个结点。while(p.next != null){} head 自己记录的
  4. 链表的查找、插入和删除.List =>
  5. LinkedList
  6. AarryList
  1. 循环链表:
  2. 循环链表是一种特殊的单链表。实际上,循环链表也很简单。它跟单链表唯一的区别就在尾结点。我们知道,单链表的尾结点指针指向空地址,表示这就是最后的结点了。而循环链表的尾结点指针是指向链表的头结点。从我画的循环链表图中,你应该可以看出来,它像一个环一样首尾相连,所以叫作“循环”链表
  1. 双向链表
  2. 单向链表只有一个方向,结点只有一个后继指针next指向后面的结点。双向链表,顾名思义,它支持两个方向,每个结点不止有一个后继指针next指向后面的结点,还有一个前驱指针prev指向前面的结点。双向链表需要额外的两个空间来存储后继结点和前驱结点的地址。所以,如果存储同样多的数据,双向链表要比单链表占用更多的内存空间。虽然两个指针比较浪费存储空间,但可以支持双向遍历,这样也带来了双向链表操作的灵活性。那相比单链表,双向链表适合解决哪种问题呢?
  3. Spring AOP 注解,最新的技术,红黑树和链表查找。lognOn JDK1.8 8的才转红黑树。最适合你的。架构师
  4. B+Tree:Mysql索引 叶子节点 双向链表

image.png

image.png

代码实现:

1.单向链表:

  1. package com.linkedList;
  2. public class MyLinkedList {
  3. private ListNode head;
  4. private int size = 0;
  5. //O(1)
  6. public void insertHead(int value) {
  7. ListNode newNode = new ListNode(value);
  8. //将新建的节点指向原始的头
  9. newNode.next = head;
  10. //将新建的节点赋值给头节点
  11. head = newNode;
  12. }
  13. //O(N)
  14. //将节点插入到position的位置 0就是插入到第0个节点 1就是第1个节点
  15. public void insertNth(int data, int position) {
  16. if (position == 0) {
  17. //头节点插入
  18. insertHead(data);
  19. } else {
  20. ListNode currentNode = head;
  21. for (int i = 1; i < position; i++) {
  22. currentNode = currentNode.next;
  23. }
  24. ListNode newNode = new ListNode(data);
  25. //插入新的节点
  26. //新的节点指向下一个节点,保证后面的节点链不会断
  27. newNode.next = currentNode.next;
  28. //将当前的节点指向新的节点
  29. currentNode.next = newNode;
  30. }
  31. }
  32. //O(1)
  33. public void deleteHead() {
  34. if (head != null) {
  35. head = head.next;
  36. }
  37. }
  38. //O(N)
  39. public void deleteNth(int position) {
  40. if (position == 0) {
  41. deleteHead();
  42. } else {
  43. ListNode cur = head;
  44. for (int i = 1; i < position; i++) {
  45. cur.next = cur;
  46. }
  47. //防止空指针
  48. if (cur.next != null) {
  49. cur.next = cur.next.next;
  50. }
  51. }
  52. }
  53. //查找
  54. public void print() {
  55. ListNode cur = head;
  56. while (cur != null) {
  57. System.out.println(cur.value+" ");
  58. cur = cur.next;
  59. }
  60. }
  61. //O(N)
  62. public void find(int data){
  63. ListNode cur = head;
  64. while (cur!=null){
  65. if(cur.value == data){
  66. System.out.println("查找到元素:"+cur.value);
  67. break;
  68. }
  69. cur.next = cur;
  70. }
  71. }
  72. }
  73. class ListNode {
  74. public int value;//值
  75. public ListNode next;//指针
  76. public ListNode(int value) {
  77. this.value = value;
  78. this.next = null;
  79. }
  80. }

2.双向链表

  1. package com.linkedList;
  2. //双向列表
  3. public class DoubleLinkedList {
  4. public DNode head;//头
  5. public DNode tail;//尾
  6. public DoubleLinkedList() {
  7. }
  8. public void insertHead(int data) {
  9. DNode newNode = new DNode(data);
  10. if (head == null) {
  11. tail = newNode;
  12. } else {
  13. head.pre = newNode;
  14. newNode.next = head;
  15. }
  16. head = newNode;
  17. }
  18. public void insertNth(int data, int position) {
  19. if (position == 0) {
  20. insertHead(data);
  21. } else {
  22. DNode cur = head;
  23. DNode newNode = new DNode(data);
  24. for (int i = 1; i < position; i++) {
  25. cur = cur.next;
  26. }
  27. newNode.next = cur.next;
  28. //防止空指针 也就是cur是最后一个节点
  29. if (cur.next != null) {
  30. cur.next.pre = newNode;
  31. }
  32. newNode.pre = cur;
  33. cur.next = newNode;
  34. }
  35. }
  36. public void deleteHead() {
  37. if(head == null){
  38. return;
  39. }
  40. if(head.next == null){
  41. head = null;
  42. }else{
  43. head.next.pre = null;
  44. }
  45. head = head.next;
  46. }
  47. public void deleteByKey(int data){
  48. DNode cur = head;
  49. while (cur.value!=data){
  50. if(cur.next==null){
  51. System.out.println("没找到节点");
  52. return ;
  53. }
  54. cur = cur.next;
  55. }
  56. if(cur== head){
  57. deleteHead();
  58. }else {
  59. cur.pre.next = cur.next;
  60. if(cur == tail){
  61. }
  62. cur.next.pre = cur.pre;
  63. }
  64. }
  65. }
  66. class DNode {
  67. public int value;
  68. //指向前一个指针
  69. public DNode pre;
  70. //指向后一个指针
  71. public DNode next;
  72. public DNode(int value) {
  73. this.value = value;
  74. this.next = null;
  75. this.pre = null;
  76. }
  77. }

3.约瑟夫问题

  1. package com.linkedList;
  2. /**
  3. * 约瑟夫问题:详细描述我会写在这里。
  4. * 课后完成。
  5. * 约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。
  6. * 现在问你最后留下的人是谁?
  7. * 比如N=6,M=5
  8. * 留下的就是1
  9. * 1 2 3 4 5 6 => 6 1 2 3 4 => 6 1 2 3 =>1 2 3 => 1 3 => 1
  10. * */
  11. public class JosefCircleMain {
  12. public static void main(String[] args) {
  13. // count(6);
  14. count2(6);
  15. }
  16. //
  17. private static void count2(int k) {
  18. //1.构造循环单列表
  19. Node head = new Node();
  20. Node cur = head;
  21. for (int i = 1; i <= k; i++) {
  22. Node tmpNode = new Node(i);
  23. cur.next = tmpNode;
  24. cur = cur.next;
  25. }
  26. cur.next = head.next;
  27. //开始遍历
  28. int w = 5;
  29. Node p = cur.next;
  30. while (p.next!=p){
  31. //1 2 3 4 5 6
  32. for (int i = 1; i < w-1; i++) {
  33. p = p.next;
  34. }
  35. System.out.println("remove node"+p.next.value);
  36. p.next = p.next.next;
  37. p = p.next;
  38. }
  39. System.out.println("left:"+p.value);
  40. }
  41. }
  42. class Node{
  43. public Node next;
  44. public int value;
  45. public Node(int value) {
  46. this.value = value;
  47. }
  48. public Node() {
  49. }
  50. }