import java.util.HashMap; import java.util.Stack; /** * Created by wst on 2017/6/30. */ public class List_Algorithm { public static void main(String[] args) { Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); Node n4 = new Node(4); Node n5 = new Node(5); Node n6 = new Node(6); n1.next = n2; n2.next = n3; n3.next = n4; n4.next = n5; n5.next = n6; Node n11 = n1; Node n12 = n2; Node n13 = n3; Node n14 = n4; Node n15 = n5; Node n16 = n6; n11.next = n12; n12.next = n13; n13.next = n14; n14.next = n15; n15.next = n16; n16.next = n13; List_Algorithm list_algorithm=new List_Algorithm(); List_Algorithm list_algorithm1=new List_Algorithm(); // System.out.println(list_algorithm.FindListLength(n1)); // list_algorithm.printLinked(list_algorithm.revLinkedList(n1)); // Node nx=list_algorithm.revLinkedList(n1); // list_algorithm.printLinked(n1); int k=0,k1=0; Node newNode1=n1; //list_algorithm.printLinked(n1); //list_algorithm.printLinked(list_algorithm.revLinkedList(n1)); // Node newNode2=list_algorithm.revLinkedList(n1); //Node newNode3=list_algorithm1.revLinkedList(newNode2); // Node newNode4=list_algorithm1.revLinkedList(newNode3); // list_algorithm.printLinked(n1); // list_algorithm.printLinked(newNode1); // list_algorithm.printLinked(newNode2); // list_algorithm1.printLinked(newNode3); // list_algorithm.printLinked(newNode4); // list_algorithm.printLinked(list_algorithm.mergeSortedListRecsion2(n1,n13)); // list_algorithm.revprintListRecsion(n1); System.out.println(list_algorithm.getFirstNodeInCycleHashMap(n11).data); } //求节点的个数 public int FindListLength(Node node){ if (node ==null) return 0; int sum=0; while(node!=null){ sum=sum+1; node=node.next; } return sum; } //反转单链表,遍历链表,取下当前节点,在新链表中倒着链接。 public Node revLinkedList(Node node1){ Node node=node1; if(node==null||node.next==null) return node; else { Node preHead=null; // Node nextHead=null; while(node!=null) { Node nextHead=node.next;//取下当前节点前,防止链表断裂,将后面链表保存 node.next=preHead; //取下当前节点,并链接新链表prehead preHead=node; //保存当前节点 node=nextHead; //将取下节点后的链表,存回node. } return preHead; } } //使用递归 public Node revLinkedList2(Node head){ if(head==null||head.next==null) return head; Node newHead=revLinkedList2(head.next); head.next.next=head; head.next=null; return newHead; } //找到链表中的倒数的第K个节点 //方法一。先统计出链表中的节点个数N,然后再找到第(N-k)个节点,就是倒数的第K个节点 public Node FindRevNode(int k,Node head){ int NodeNum=0; Node q=head; while (head!=null){ NodeNum=NodeNum+1; head=head.next; } System.out.println(NodeNum); int flag=NodeNum-k; //System.out.println(flag); while (flag>0){ q=q.next; //head=head.next; flag--; } return q; } //方法二、使用两个链表first,second,先让first链表走到正向的K个节点,此时两个节点的距离差刚好的K-1个, //然后两个链表同时向前移动,当first链表走到最后一个节点时,second的链表刚好访问到的是倒数第K的节点 public Node FindRevNode2(int k,Node head){ Node first=head; Node second=head; if(k<1||head==null) return null; while(k>1&&first!=null){ first=first.next; k--; } if(k>1||first==null)//如果K大于链表的长度,那么此时first一定为null,所以返回null return null; while (first.next!=null){ first=first.next; second=second.next; } return second; } //查找链表的中间节点,与上面相类似,只是first链表走两步,而second链表走一步, //当first链表走到最后节点时,second链表就走到中间节点 public Node FindMiddNode(Node head){ if(head==null||head.next==null) return head; Node first=head; Node second=head; while (first!=null){ first=first.next; second=second.next; if(first!=null) first=first.next; } return second; } //从尾部打印单链表,这种颠倒顺序的问题,我们应该想到栈,后进先出。所以,有两个方法,第一, //自己使用栈,第二就是让系统使用栈,也即是递归调用。 public void revprintListStack(Node head){ Stack<Node> stack=new Stack<>(); while(head!=null){ stack.push(head); head=head.next; } //System.out.println(stack.pop().data); while(!stack.isEmpty()){ System.out.print(stack.pop().data); } System.out.println(""); } //递归方法从尾部打印链表。 public void revprintListRecsion(Node head){ if (head==null) return; revprintListRecsion(head.next); System.out.print(head.data); } //合并链表。针对这个问题,要充分考虑好各种情况,当两个链表都为空时,或者 //一个为空时,怎么去处理要注意。 public Node mergeSortedList(Node head1,Node head2){ Node newHead=null; if (head1==null) return head2; else if (head2==null) return head1; else { if (head1.data < head2.data) { newHead=head1; head1=head1.next; } else { newHead=head2; head2=head2.next; } } Node newHead2=newHead; while ((head1!=null)&&(head2!=null)){ if(head1.data<head2.data){ newHead2.next=head1; head1=head1.next; // System.out.print(newHead2.data+"*"); }else { newHead2.next=head2; head2=head2.next; // System.out.print(newHead2.data+"."); } newHead2=newHead2.next; // newHead2.next=null; } if (head1!=null) newHead2.next=head1; else newHead2.next=head2; // System.out.println("han"); return newHead; } //递归实现合并, public Node mergeSortedListRecsion(Node head1,Node head2){ if (head1==null) return head2; if (head2==null) return head1; Node newHead=null; if (head1.data<head2.data){ newHead=head1; newHead.next=mergeSortedListRecsion(head1.next,head2); }else { newHead=head2; newHead.next=mergeSortedListRecsion(head1,head2.next); } return newHead; } //递归,不新建链表 public Node mergeSortedListRecsion2(Node head1,Node head2){ if (head1==null) return head2; if (head2==null) return head1; //Node newHead=null; if (head1.data<head2.data){ head1.next=mergeSortedListRecsion(head1.next,head2); return head1; }else { head2.next=mergeSortedListRecsion(head1,head2.next); return head2; } // return newHead; } //判断单链表是否有环。如果链表有环,那么遍历改环的话将走不到头。为此我们想到是否可以,使用 //两个链表,让first链表走两步,second链表走一步,那么first链表和second链表一定会再次相遇。 //以此来判断是否有环 public boolean hasCycle(Node head){ if(head==null) return false; else { Node first=head; Node second=head; while (first.next!=null&&first!=null){//用first来判断,当无环时更加节省时间复杂度 first=first.next.next; second=second.next; //second=second.next; if(first==second) return true; } return false; } } //判断两个单链表是否相交。如果两个链表相交于某一节点,那么这一节点后面的所有节点 //都为两个链表共有(最差情况是只有最后一个节点相共有),因为从前面遍历不方便判断, // 因此我们从最差的情况判断,判断最后一个节点是否为两个链表共有,如果最差情况都满足 //那么这两个单链表一定相交 public boolean isIntersected(Node head1,Node head2){ if(head1==null||head2==null) return false; else{ while (head1.next!=null) { head1=head1.next; } while (head2.next!=null){ head2=head2.next; } if (head1==head2) return true; else return false; } } //判断两个单链表相交的第一个节点,方法1.可以使用map来存储第一个链表, // 再通过contains.Key()方法来判断是否与第二个链表相同 //方法二。可以使用栈来存储两个链表,然后弹栈比较两链表节点,当遇到最后一个不相等的节点时, //说明前一个节点就是相交的第一个节点 //方法三。分被遍历两个链表,保存长度len和最后一个节点,若最后一个节点相等那么 // 判断哪个链表要长一些,然后长的那个链表走len1-len2步,此时两个链表的长度就一样了,此时来 //一起遍历,直到遇到相同的节点。 public Node getFistCommonNode1(Node pHead1,Node pHead2){ if (pHead1 == null || pHead2 == null) { return null; } Stack<Node> stack1 = new Stack<>(); Stack<Node> stack2 = new Stack<>(); while(pHead1.next != null) { stack1.push(pHead1); pHead1 = pHead1.next; } stack1.push(pHead1); while (pHead2.next != null) { stack2.push(pHead2); pHead2 = pHead2.next; } stack2.push(pHead2); Node commonListNode = null; while (!stack1.isEmpty() && !stack2.isEmpty() && stack1.peek() == stack2.peek() ) { stack2.pop(); commonListNode = stack1.pop(); } return commonListNode; } //方法一 public Node getFirstCommonNode(Node pHead1,Node pHead2){ Node head1=pHead1; Node head2=pHead2; HashMap<Node,Boolean> map=new HashMap<>(); while (head1.next!=null){ map.put(head1,null); head1=head1.next; } map.put(head1,null); while (head2!=null){ if(map.containsKey(head2)) return head2; head2=head2.next; } return null; } //已知单链表中存在环,求进入环的第一个节点 //方法1.使用map来做 //方法2.使用快慢指针runner来进行。 public Node getFirstNodeInCycleHashMap(Node head){ HashMap<Node,Boolean> map1=new HashMap<Node,Boolean>(); //boolean flag=false; // nodeHashMap.put(head,0); while (head!=null){ if(map1.containsKey(head)) { return head; } else{ map1.put(head,true); head=head.next; } } return null; } //runner // first的速度是second的两倍。假设second移动到进入环的第一个节点,距离开始节点相差k, // 那么first此时在环内距离进入环的第一个节点的距离是x(x=mod(k,环的长度length)), // 此时second处于环中0步,first领先于second为x步,second落后于first为length-x步,因此再次 // 相遇时(即first追上second时),需要走length-x次(frist每次必second多走一步),因此这个相遇点 // 再向前走x步就到环入口。如果此时开始节点和second同时向前移动,那么必定会在环入口相遇。此时相遇 // 的节点就是,环的第一个节点。(k=x+m*length),所以若环很小,也满足。 public Node getFirstNodeInCycleRunner(Node head){ Node first=head; Node second=head; while (first!=null&&first.next!=null){ first=first.next.next; second=second.next; if (first==second) break; } if(first==null||first.next==null) return null; first=head; while (first!=second){ first=first.next; second=second.next; } return first; } //给定一个单链表,和一个节点beDeletedNode,要求实现时间复杂度为O(1),删除节点 //beDeleteNode.对于链表,每个节点的结构都是一样的,所以我们可以要删除节点的下一个 //节点,复制到该节点,然后删除下一个节点即可。但是要注意删除节点是最后一个节点的情况。 // 这时候要单独考虑,因为其下一个节点为null。因此只能找到上一个节点,然后让其head.next=null // 来删除该节点(但此时的时间复杂度,就不为O(1),而是O(n)了,因此可以在 // 删除最后一个节点标记为false)。 public boolean deleteNode(Node head,Node beDeleteNode){ if(beDeleteNode==null) return false; if (beDeleteNode.next!=null)//删除节点,除去最后一个节点的情况 { beDeleteNode.data=beDeleteNode.next.data;//将下一节点复制给删除节点 beDeleteNode.next=beDeleteNode.next.next; return true; } else {//删除的是最后一个节点的情况 if(beDeleteNode==head)//链表中只有一个节点的情况 { head = null; return true; } else { Node phead=head; while(phead.next!=beDeleteNode){//找到上一个节点 phead=phead.next; } phead.next=null;//删除该节点 return true; } } } public void printLinked(Node head){ while(head!=null) { System.out.print(head.data); head=head.next; } System.out.println(""); } } class Node { public int data; public Node next; Node(int data) { this.data = data; this.next = null; } }
数据结构中有关链表的题目
最新推荐文章于 2022-07-13 19:41:04 发布