LintCode(2):单链表相关操作

来源:互联网 发布:网络差评师 编辑:程序博客网 时间:2024/05/09 14:25

单链表的相关操作是面试中经常被提问的内容,也是反映应聘者数据结构基本能力很好的途径,因此系统归纳总结单链表的一些常用操作和实现,是十分必要的。

而且在实现单链表各种操作的过程中,看到了变量和指针的重要性,引入适当的变量和指针或者引用,来记录编程中的中间状态,会大大简化编程逻辑

package DataStructure;import java.util.Stack;import javax.swing.text.AbstractDocument.LeafElement;//Java语言实现单链表以及各种操作public class LinkList {// 实际上链表类中维护一个头节点类即可private Node head;// 这个节点表示当前节点的索引,可以理解为链表中最后一个节点,在添加节点的时候使用private Node current;// 1.向链表中添加节点,肯定是添加到链表结尾public void add(int data) {// 如果头节点为空,表示链表还没开始创建。在链表的操作中,记住永远要判断头结点这个特殊节点// 因为Java中没有指针,名称实际上也是引用,所以为了好理解,可以将对象的名称当成指针来理解if (head == null) {head = new Node(data);current = head;} else {current.next = new Node(data);// 更新当前节点的指向current = current.next;}}// 2.删除链表的最后一个节点public void delete() {if (head == null)return;if (head == current) {head = null;current = null;} else {// 引入前一个节点,然后遍历递进Node prev = head;while (prev.next != current) {prev = prev.next;}prev.next = null;// 千万不要忘记将current更新为最新current = prev;}}// 3.遍历链表,不一定从head开始遍历,所以传入的node表示遍历开始节点public void print(Node node) {// 对传进来的参数首先做非空非null判断,是良好的编程习惯,防止抛出空指针异常if (node == null)return;// 用来做遍历操作的引用,局部变量Node temp = node;while (temp != null) {System.out.print(temp.data + "->");temp = temp.next;}System.out.println("");}// 4.求单链表的长度public int getLength() {if (head == null)return 0;int length = 0;Node temp = head;while (temp != null) {length++;temp = temp.next;}return length;}// 5.查找倒数第K个节点public Node findLastNode(int k) {// 判断传入参数K的值,如果为0,则返回nullif (k == 0)return null;// 定义两个节点,用两个节点的差值来定位倒数第K个Node first = head;Node second = head;for (int i = 0; i < k - 1; i++) {second = second.next;}if (second == null)return null;while (second.next != null) {second = second.next;first = first.next;}return first;}// 6.查找链表的中间节点public Node findMidNode() {Node first = head;Node second = head;while (second != null && second.next != null) {// 这样对于偶数个节点,是n/2+1first = first.next;second = second.next.next;}return null;}// 7.两个有序单链表合成一条有序单链表public Node mergeLinkList(Node head1, Node head2) {if (head1 == null && head2 == null) {return null;}if (head1 == null) {return head2;}if (head2 == null) {return head1;}Node head = null; // 新链表的头结点Node current = null;// current指向新链表的节点// head1和head2不断的迭代递进if (head1.data <= head2.data) {head = head1;current = head;head1 = head1.next;} else {head = head2;current = head;head2 = head2.next;}// 只要由一个走到最后的节点就停止循环while (head1 != null && head2 != null) {if (head1.data <= head2.data) {current.next = head1;current = current.next;head1 = head1.next;} else {current.next = head2;current = current.next;head2 = head2.next;}}if (head1 != null) {current.next = head1;}if (head2 != null) {current.next = head2;}return head;}// 8.翻转单链表 出现频率极高public Node reverseList(Node head) {if (head == null || head.next == null)return head;Node current = head;// 保持前一个节点prevNode prev = null;// 在前面的正序遍历中,需要定义一个prev指针,这里需要后面的节点,则需要一个next指针Node next = head.next;while (current != null) {// 保存下一个节点next = current.next;// 将当前节点指向前一个节点current.next = prev;// 做完一次操作,两个指针都往前迭代prev = current;current = next;}return prev;}// 9.从尾到头打印链表,对于这种颠倒顺序的,使用栈来完成,要么自己实现栈,要是使用系统的栈,也就是递归// 自己使用栈,基于循环实现,代码更好// 如果使用递归,栈深度太大容易溢出public void reversePrint(Node head) {if (head == null)return;Stack<Node> stack = new Stack<Node>(); // 新建一个栈,java中已经实现了stack类,实际编程中可以使用Node current = head;while (current != null) {stack.push(current);// 压栈current = current.next;}while (stack.size() > 0) {System.out.println(stack.pop().data);// 出栈}}// 使用递归,代码简洁public void reversePrintByRecusion(Node head) {// 既是判断参数条件,也是递归终止条件 递归的最终结束就是遇到return,虽然这个return没有返回任何数据,这时压入栈的数据开始返回if (head == null)return;reversePrintByRecusion(head.next);System.out.println(head.data);}// 10.判断单链表是否有环public boolean hasCycle(Node head) {if (head == null)return false;Node first = head;Node second = head;while (second != null) {first = first.next;second = second.next.next;if (first == second) {return true; // 一旦两个指针相遇,表示有环}}return false;}// 11.得到有环链表中两个指针的相遇节点public Node hasMeetPoint(Node head) {if (head == null) {return null;}Node first = head;Node second = head;while (second != null) {first = first.next;second = second.next.next;if (first == second) { // 一旦两个指针相遇,说明链表是有环的return first; // 将相遇的那个结点进行返回}}return null;}// 12.得到环的长度public int getCycleLength(Node node) {if (node == null)return 0;Node current = node;int length = 0;while (current != null) {// 必须先迭代一步,再判断是否相等,否则会一直循环current = current.next;length++;if (current == node) {return length;}}return length;}// 13.获取环的起始点 需要用到判断是否有环、得到相遇点已经得到环的长度这几个方法的配合,再用追击迫近的思想求出起点// 本质上还是迫近追击,找到倒数第K个值的问题public Node getCycleStart(Node head, int cycleLength) {if (head == null)return null;Node first = head;Node second = head;for (int i = 0; i < cycleLength; i++) {second = second.next;}while (first != null && second != null) {first = first.next;second = second.next;if (first == second)return first;// 两个指针相遇表示在起始点回合}return null;}// 方法:获取单链表的长度public int getLength(Node head) {if (head == null) {return 0;}int length = 0;Node current = head;while (current != null) {length++;current = current.next;}return length;}// 14.得到两个单链表的相交节点 快慢指针 追击迫近public Node getFirstCommonNode(Node head1, Node head2) {if (head1 == null || head2 == null) {return null;}int length1 = getLength(head1);int length2 = getLength(head1);int lengthDif = 0;Node longHead = null;Node shortHead = null;//找到长短链表的头部和长度差值,分别保存在自定义的变量中if (length1 > length2) {longHead = head1;shortHead = head2;lengthDif = length1 - length2;} else {longHead = head2;shortHead = head1;lengthDif = length2 - length1;}//将较长的那个链表的指针向前走length个距离 for (int i = 0; i < lengthDif; i++) {  longHead = longHead.next; }  //将两个链表的指针同时向前移动 while (longHead != null && shortHead != null) {  if (longHead == shortHead) { //第一个相同的结点就是相交的第一个结点   return longHead;  }  longHead = longHead.next;  shortHead = shortHead.next; }  return null;}public static void main(String[] args) {LinkList list1 = new LinkList();LinkList list2 = new LinkList();LinkList list3 = new LinkList();// 向LinkList中添加数据for (int i = 0; i < 5; i++) {list1.add(i);}for (int i = 10; i < 5; i++) {list2.add(i);}list3.print(list3.mergeLinkList(list1.head, list2.head));}// 链表节点类,内部类实现,包含数据域和指针域class Node {int data; // 数据域Node next;// 指针域public Node(int data) {this.data = data;}}}


0 0
原创粉丝点击