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


代码实现:
1.单向链表:
package com.linkedList;public class MyLinkedList { private ListNode head; private int size = 0; //O(1) public void insertHead(int value) { ListNode newNode = new ListNode(value); //将新建的节点指向原始的头 newNode.next = head; //将新建的节点赋值给头节点 head = newNode; } //O(N) //将节点插入到position的位置 0就是插入到第0个节点 1就是第1个节点 public void insertNth(int data, int position) { if (position == 0) { //头节点插入 insertHead(data); } else { ListNode currentNode = head; for (int i = 1; i < position; i++) { currentNode = currentNode.next; } ListNode newNode = new ListNode(data); //插入新的节点 //新的节点指向下一个节点,保证后面的节点链不会断 newNode.next = currentNode.next; //将当前的节点指向新的节点 currentNode.next = newNode; } } //O(1) public void deleteHead() { if (head != null) { head = head.next; } } //O(N) public void deleteNth(int position) { if (position == 0) { deleteHead(); } else { ListNode cur = head; for (int i = 1; i < position; i++) { cur.next = cur; } //防止空指针 if (cur.next != null) { cur.next = cur.next.next; } } } //查找 public void print() { ListNode cur = head; while (cur != null) { System.out.println(cur.value+" "); cur = cur.next; } } //O(N) public void find(int data){ ListNode cur = head; while (cur!=null){ if(cur.value == data){ System.out.println("查找到元素:"+cur.value); break; } cur.next = cur; } }}class ListNode { public int value;//值 public ListNode next;//指针 public ListNode(int value) { this.value = value; this.next = null; }}
2.双向链表
package com.linkedList;//双向列表public class DoubleLinkedList { public DNode head;//头 public DNode tail;//尾 public DoubleLinkedList() { } public void insertHead(int data) { DNode newNode = new DNode(data); if (head == null) { tail = newNode; } else { head.pre = newNode; newNode.next = head; } head = newNode; } public void insertNth(int data, int position) { if (position == 0) { insertHead(data); } else { DNode cur = head; DNode newNode = new DNode(data); for (int i = 1; i < position; i++) { cur = cur.next; } newNode.next = cur.next; //防止空指针 也就是cur是最后一个节点 if (cur.next != null) { cur.next.pre = newNode; } newNode.pre = cur; cur.next = newNode; } } public void deleteHead() { if(head == null){ return; } if(head.next == null){ head = null; }else{ head.next.pre = null; } head = head.next; } public void deleteByKey(int data){ DNode cur = head; while (cur.value!=data){ if(cur.next==null){ System.out.println("没找到节点"); return ; } cur = cur.next; } if(cur== head){ deleteHead(); }else { cur.pre.next = cur.next; if(cur == tail){ } cur.next.pre = cur.pre; } }}class DNode { public int value; //指向前一个指针 public DNode pre; //指向后一个指针 public DNode next; public DNode(int value) { this.value = value; this.next = null; this.pre = null; }}
3.约瑟夫问题
package com.linkedList;/** * 约瑟夫问题:详细描述我会写在这里。 * 课后完成。 * 约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。 * 现在问你最后留下的人是谁? * 比如N=6,M=5 * 留下的就是1 * 1 2 3 4 5 6 => 6 1 2 3 4 => 6 1 2 3 =>1 2 3 => 1 3 => 1 * */public class JosefCircleMain { public static void main(String[] args) {// count(6); count2(6); } // private static void count2(int k) { //1.构造循环单列表 Node head = new Node(); Node cur = head; for (int i = 1; i <= k; i++) { Node tmpNode = new Node(i); cur.next = tmpNode; cur = cur.next; } cur.next = head.next; //开始遍历 int w = 5; Node p = cur.next; while (p.next!=p){ //1 2 3 4 5 6 for (int i = 1; i < w-1; i++) { p = p.next; } System.out.println("remove node"+p.next.value); p.next = p.next.next; p = p.next; } System.out.println("left:"+p.value); }}class Node{ public Node next; public int value; public Node(int value) { this.value = value; } public Node() { }}