1.注意:
若是频繁访问可以使用ArrayList,因为使用序号便可以找到
若是频繁地增删查改可以使用LinkList比较方便
2.链表
链表在物理上不一定连续,但在逻辑上一定连续(因为有next的存在)
建立自己的单向链表:
package lianbiao; import java.util.Stack; public class TestSingleList { static class Node{ public int val; public Node next; //带参的构造方法 public Node (int val){ this.val = val; } } public Node head;//表示存储当前链表头结点的引用 public void createList(){ //以穷举的方式创建链表 Node node1 = new Node(10); Node node2 = new Node(12); Node node3 = new Node(23); Node node4 = new Node(34); node1.next = node2; node2.next = node3; node3.next = node4; head = node1; } //====================================================================================显示列表============================ public void display(){ Node cur = this.head;//用cur代替它的头节点 while(cur != null){ System.out.print(cur.val +" "); cur = cur.next; } System.out.println( ); } public void display(Node Curhead){ //从指定节点打印链表 Node cur = Curhead;//用cur代替它的头节点 while(cur != null){ System.out.print(cur.val +" "); cur = cur.next; } System.out.println( ); } //====================================================================================查找是否包含关键字key============================ public boolean contains(int key){ Node cur = this.head; while(cur != null){ if(cur.val == key){ return true; } cur = cur.next; } return false; } //====================================================================================得到链表的大小============================ public int size(){ Node cur = this.head; int count = 0; while(cur != null){ count++; cur = cur.next; } return count; } //====================================================================================头插法============================ public void addFirst(int data){ Node node = new Node(data); node.next = head; head = node; } //====================================================================================尾插法============================ public void addLast(int data){ Node node = new Node(data); if(head == null){ head = node; }else{ Node cur = head; while (cur.next!=null){ cur = cur.next; } cur.next = node; } } //====================================================================================任意位置插入,第一个数据节点为0下标============================ private void checkIndex(int index){ //先检查index是否合法 if(index<0 || index>size()){ throw new IndexNotLeagleException("index位置不合法"); } } private Node findIndexSubOfOne(int index){ //先找到cur的位置 int count = 0; Node cur = head; while(count!=index-1){ count++; cur = cur.next; } return cur; } public void addIndex(int index,int data){ checkIndex(index); if(index == 0){ addFirst(data);//头插 return; } if (index == size()){ addLast(data);//尾插 return; } //在中间插入节点 Node node = new Node(data); Node cur = findIndexSubOfOne(index); node.next=cur.next; cur.next=node; } //====================================================================================删除第一次出现关键词key的节点============================ private Node searchPrevOfKey(int key){ Node cur = head; while(cur.next!=null){ if(cur.next.val == key){ return cur; } cur = cur.next; } return null; } public void remove(int key){ //当头节点为要删除的值 if(head.val == key){ head = head.next; return; } //当要删除的值不是头节点 Node cur=searchPrevOfKey(key); if(cur==null){ return; } // Node del = cur.next; // cur.next = del.next; // 上面两句相当于下面一句 cur.next=cur.next.next; } //=============================================================================删除所有为key的节点============================ public void removeAllKey(int key){ //处理不是头节点的节点 Node prev = head; Node cur = head.next; if(cur==null){ return; } while(cur!=null){ if(cur.val == key){ prev.next=cur.next; cur = cur.next; }else{ prev = cur; cur=cur.next; } } //重点:::处理头节点,放在后面比较好这样就只需要遍历链表一遍,因为如果放在前面会增加复杂度!!!! //另外一种节点:是先增加一个头节点,然后就可以直接进行删除,最后删除头节点即可 if(head.val == key){ head = head.next; return; } } //========================================================================清空链表============================== public void clear(){ //1. head = null这样的方式也可以,但是简单粗暴 //2. Node cur=head; while(cur!=null){ Node curNext = cur.next; cur.next = null; cur = curNext; } head = null; } //========================================================================反转链表(两种方式)============================== // public void reverseList(){ // if(head==null) return ; // if(head.next==null) return; // Node cur = head.next; // head.next=null; // while(cur!=null){ // Node curNext = cur.next; // cur.next=head; // head = cur; // cur = curNext; // } // } public Node reverseList(){ if(head==null) return null; if(head.next==null) return head; Node cur = head.next; head.next=null; while(cur!=null){ Node curNext = cur.next; cur.next=head; head = cur; cur = curNext; } return head; } //给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。 public Node middleNode(){ if(head==null) return null; if(head.next==null) return head; Node fast=head; Node slow = head; while (fast!=null &&fast.next!=null){ fast=fast.next.next; slow=slow.next; } return slow; } //输入一个链表,输出该链表中倒数第k个结点。 public Node FindKthToTail(int k){ if(k<=0 || head == null){ return null; } Node fast = head; Node slow = head; while(k-1!=0){ fast = fast.next; if(fast == null){ return null;//说明k太大了!!! } k--; } while(fast.next!=null){ fast = fast.next; slow = slow.next; } return slow; } // 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 public Node mergeTwoLists(TestSingleList testSingleList1, TestSingleList testSingleList2){ Node newHead = new Node(-1);//虚拟节点 Node tmp=newHead; Node head1=testSingleList1.head; Node head2=testSingleList2.head; while(head1!=null && head2!=null){ if(head1.val < head2.val){ tmp.next=head1; head1=head1.next; tmp=tmp.next; }else{ tmp.next = head2; head2=head2.next; tmp=tmp.next; } } if(head1!=null){ tmp.next=head1; } if(head2!=null){ tmp.next=head2; } newHead=newHead.next; return newHead; } //编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点(第一部分)排在大于或等于x的结点(第二部分)之前 。 public Node partition(int x){ //第一部分 Node bs=null; Node be=null; //第二部分 Node as=null; Node ae=null; Node cur = head; while(cur!=null){ if(cur.val<x){ if(bs==null){ //说明是第一段的第一次插入 bs=cur; be=cur; }else{ be.next = cur; be=be.next; } }else{ if(as==null){ //说明是第二段的第一次插入 as=cur; ae=cur; }else{ ae.next=cur; ae=ae.next; } } cur=cur.next; } if(bs==null){ //如果不存在前半段 return as; } be.next=as; if(as!=null){ //as不为null说明存在后半段,使最后一个节点为空 ae.next=null; } return bs; } //将递归转化为循环. 比如:逆序打印链表 public void printList(Node head){ if(head == null){ return; } if(head.next == null){ System.out.print(head.val+" "); return; } printList(head.next); System.out.print(head.val+" "); } //非递归实现,即模仿栈 public void printList2(){ Stack<Node> stack = new Stack<>(); Node cur = head; while(cur != null){ stack.push(cur);//入栈 cur = cur.next; } // while(!stack.empty())相当于while(stack.size() !=0) while(stack.size() !=0){ Node top = stack.pop();//出栈 System.out.print(top.val +" "); } System.out.println( ); } }
3.双向链表
建立自己的双向链表:
package Bilianbiao; public class MyLinkedList { static class ListNode{ public int val; public ListNode prev; public ListNode next; public ListNode(int val){ this.val = val; } } public ListNode head; public ListNode last; public void display(){ ListNode cur = head; while(cur!=null){ System.out.print(cur.val +" "); cur=cur.next; } System.out.println(); } //头插法 public void addFirst(int data){ ListNode node = new ListNode(data); if(head == null){ head=node; last=node; }else{ node.next=head; head.prev=node; head=node; } }; //尾插法 public void addLast(int data){ ListNode node = new ListNode(data); if(head == null){ head=node; last=node; }else{ last.next=node; node.prev=last; last=node; } }; //任意位置插入,第一个数据节点为0号下标 private ListNode findIndex(int index){ ListNode cur = head; while(index!=0){ cur = cur.next; index--; } return cur; } public void addIndex(int index,int data){ //1.检查index是否合法 if(index<0 || index>size()){ throw new IndexNotLeagleException1("双向链表index不合法!!!"); } if(index==0){ addFirst(data); return; } if(index==size()){ addLast(data); return; } //2.获取当前index位置的节点的地址 ListNode cur=findIndex(index); ListNode node = new ListNode(data); node.next=cur; cur.prev.next = node; node.prev = cur.prev; cur.prev =node; }; //查找是否包含关键字key是否在单链表当中 public boolean contains(int key){ ListNode cur = head; while(cur!=null){ if(cur.val == key){ return true; } cur=cur.next; } return false; }; //删除第一次出现关键字为key的节点 public void remove(int key){ ListNode cur = head; while(cur!=null){ //找到了key的位置 if(cur.val==key){ //针对头节点 if(cur==head){ head = head.next; if(head!=null){ //防止只有一个节点 head.prev = null; } }else{ cur.prev.next=cur.next; if(cur.next!=null){ //删除的不是尾巴节点 cur.next.prev = cur.prev; }else{ //删除的是尾巴节点 last=cur.prev; } } return; } cur = cur.next; } }; //删除所有值为key的节点 public void removeAllKey(int key){ ListNode cur = head; while(cur!=null){ //找到了key的位置 if(cur.val==key){ //针对头节点 if(cur==head){ head = head.next; if(head!=null){ //防止只有一个节点 head.prev = null; } }else{ cur.prev.next=cur.next; if(cur.next!=null){ //删除的不是尾巴节点 cur.next.prev = cur.prev; }else{ //删除的是尾巴节点 last=cur.prev; } } } cur = cur.next; } }; //得到单链表的长度 public int size(){ ListNode cur = head; int count = 0; while(cur!=null){ count++; cur=cur.next; } return count; }; //清空 public void clear(){ ListNode cur=head; while(cur!=null){ ListNode curNext1 = cur.next; cur.next = null; cur.prev = null; cur = curNext1; } head = null; last =null; // 2.清空的另外一种方法 // ListNode cur1=head; // ListNode cur2=last; // while(cur1!=null){ // ListNode curNext1 = cur1.next; // cur1.next = null; // cur1 = curNext1; // } // head = null; // while(cur2!=null){ // ListNode curNext2 = cur2.prev; // cur2.prev = null; // cur2 = curNext2; // } // last =null; }; }
4. ArrayList和LinkedList的区别