链表
链表是一种线性结构
上述分别为链表的逻辑结构和内存结构(实际在内存中存储顺序是不连续的)
链表的的每一个节点有两部分组成,第一部分存储相应的数据,另一部分存储下一个节点的地址,最后一个节点的next指向null
链表的特点是增删快,查找慢
双向链表
public class SingleNode { //双向链表 //相对于单向链表来讲有两个方向可以操作链表 //两个方向定义头结点和尾节点 class DoubkeLikendList{ Node head = new Node(0,null); Node tail = new Node(0,null); public void add(Node node){ Node temp = head; while(true){ if(temp.next==null){ temp.next=node; //与单向链表相同,将最后一个节点的next指向新加入的节点 node.pre=temp //将新加入的节点的上一个指向此时的temp(新加入的上一个) tail=node; break; } temp=temp.next; } } public void change(int no){ //按照编号修改姓名 //与单向链表类似 Node temp = head; while(true){ if(temp.no==no){ temp.name="新名字"; break; } if(temp.next==null){ System.out.println("没有要找到删除的节点"); break; } temp=temp.next; } } //按照指定编号删除节点 //相对于单向链表来讲,可以实现自我删除,而单向链表需要一个辅助节点 public void delete(int no){ Node temp = head; while(true){ if(temp.no==no){ if(temp.pre==null){ temp.next.pre=temp.pre; //防止空指针异常 }else if(temp.next==null){ temp.pre.next=temp.next; //防止空指针异常 }else{ temp.next.pre=temp.pre; //将该节点的下一个的前一个指向给节点的前一个 temp.pre.next=temp.next; //将该节点的前一个的下一个指向给节点的下一个 //经过上面两步以后该节点就成为一个“垃圾”,有JVM自动回收 } break; } if(temp.next==null){ System.out.println("没有要找到删除的节点"); break; } temp=temp.next; } } public void allNode(){ //利用尾节点遍历 Node temp = tail; while(true){ if(temp.next==null){ System.out.println(temp); break; } System.out.println(temp); temp=temp.next; } } } class Node{ public int no; public String name; public Node next;//指向该节点的下一个节点 public Node pre;//指向该节点的前一个节点 public Node(int no , String name) { this.no = no; this.name=name; } @Override public String toString() { return "Node{" + "no=" + no + ", name='" + name ; } } }
循环链表
、、最后一个节点指向第一个节点构成一个环形
public class CircleNode { //最后一个节点的next指向第一个节点 /* 约瑟夫问题: 约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将出队,最后剩下一个。 */ class MethodYuesefu{ Node2 first; public void addN(int N){ //按输入的N,创建指定大小的初始链表 if(N<1){ System.out.println("输入的数据不合法"); return; } Node2 assman = null;//辅助节点 for (int i = 1; i < N+1; i++) { Node2 man = new Node2(i); if(i==1){ first=man; first.setNext(first); assman = first; //只有一个数据的链表,自我构成循环 }else{ assman.setNext(man); man.setNext(first); //将新加入的节点的next指向第一个构成循环(新加入的一定是最后一个) assman=man; } } } public void allMan(){ Node2 temp = first; if(first==null){ System.out.println("链表为空~~"); return; } while(true){ System.out.println(temp); if(temp.getNext()==first){ //遍历结束条件是重新找到了第一个节点 break; } temp=temp.getNext(); } } /** * * @param startNo 从第几个编号开始数 * @param num 每一次数几个数 * @param N 总人数 */ public void countMan(int startNo,int num,int N){ if(first==null|| startNo<1||startNo>N){ System.out.println("输入的数据不符合要求"); return; } Node2 helper = first;//用来指向first的前一个节点 while(true){ //找到first的前一个元素,并将其赋值给helper if (helper.getNext()==first){ break; } helper=helper.getNext(); } for (int i = 0; i < startNo-1; i++) { //将first移到开始的位置 first=first.getNext(); helper = helper.getNext(); } while(true){ if(helper==first){ //只剩下一个数据 System.out.println("剩下的编号"); break; } for (int i = 0; i <num-1; i++) { //数数 first=first.getNext(); helper = helper.getNext(); } System.out.println("出圈:"+first.getNo()); first=first.getNext(); helper.setNext(first); //将数到的节点删除,直接将helpter指向新first,那么原新的first就访问不到了成为了垃圾 } } } class Node2{ private int no; private Node2 next; public Node2(int no) { this.no = no; } @Override public String toString() { return "Node2{" + "no=" + no + '}'; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public Node2 getNext() { return next; } public void setNext(Node2 next) { this.next = next; } } }