单链表的基本操作与算法(Java实现)

一直都是用c来实现单链表的基本操作和算法的,今天突然想使用Java来实现下,想起早上面试的穆迪姐姐,说写博客是很好的习惯,很受鼓舞,所以利用晚上的时间简单整理了下。

package linknode;

import java.util.Scanner;
import java.util.Stack;

/** 
 *  
 * @author helloway 
 * java中链表的基本操作与算法 
 * 1. 求单链表中结点的个数: getListLength  
 * 2. 将单链表反转: reverseList(非递归)
 * 3. 查找单链表中倒数第K个节点: findkthNode
 * 4. 查找单链表的中间节点: findMiddleNode  
 * 5. 从尾到头打印单链表: reversePrintStack(非递归),reversePrintR(递归)  
 * 6. 合并两条各自有序的单链表(递归): mergeR(递归), merge(非递归)  
 * 7. 对单链表进行排序,listSort(归并),insertionSortList(插入) 
 * 8. 判断一个单链表中是否有环: hasCycle  
 * 9. 已知一个单链表中存在环,求进入环中的第一个节点: entryNodeOfLoop 
 * 10. 单链表排序,insertSortList(插入)  
 */  

public class MyLinklist {
	public static class Node{
		int val;
		Node next;
		public Node(int val){
			this.val=val;
		}
	}
	
		
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		Node head=null;
		Node temp=null;
		while (scan.hasNextInt()) {
			int val=scan.nextInt();
			if (val==0) {
				break;
			}
			
			if (head==null) {
				head = new Node(val);
			    temp=head;
			}else {
				temp.next=new Node(val);
				temp=temp.next;
			}
		    
		}
		
		scan.close();
		MyLinklist myLinklist = new MyLinklist();
		//求单链表中结点的个数: getLength 
		//System.out.println(myLinklist.getLength(head));
		
		//求反转后的单链表: reverseList(非递归)
		//System.out.println(myLinklist.reverseList(head).val);
		
		//查找单链表中倒数第K个节点: findkthNode
		//System.out.println(myLinklist.findkthNode(head,3).val);
		
		//查找单链表的中间节点: findMiddleNode
		//System.out.println(myLinklist.findMiddleNode(head).val);
		
		//从尾到头打印单链表: reversePrintR(递归)
		//myLinklist.reversePrintR(head);
		
		//从尾到头打印单链表: reversePrintStack(利用栈,非递归遍历)
		//myLinklist.reversePrintStack(head);
		
		//判断单链表是否有环
		//System.out.println(myLinklist.hasCycle(head));
	}
	
	//求单链表中结点的个数: getLength 
	public int getLength(Node head) {
		int len=0;
		if (head==null) {
			return len;
		}
		Node node = head;
		while (node!=null) {
			len++;
			node=node.next;			
		}
		
		return len;
	}
	
	//求反转后的单链表: reverseList(非递归)
	public Node reverseList(Node head){
		Node reverseHead = null;
		Node pNode = head;
		Node pPrev = null;
		while (pNode!=null) {
			Node pNext = pNode.next;
			if (pNext==null) {
				reverseHead=pNode;
			}
			pNode.next = pPrev;
			
			pPrev = pNode;
			pNode=pNext;
		}
		return reverseHead;
	}
	
	//求单链表中倒数第K个节点: findkthNode
	public Node findkthNode(Node head,int k){
		if (head==null||k<=0) {
			return null;
		}
		
		Node fst = head;
		for (int i = 0; i < k-1; i++) {
			if (fst.next!=null) {
				fst=fst.next;
			}else {
				return null;
			}
		}
		
		Node sec = head;
		while(fst.next!=null){
			fst=fst.next;
			sec=sec.next;
		}
		return sec;
	}
	
	//查找单链表的中间节点: findMiddleNode
	public Node findMiddleNode(Node head){
		if (head==null||head.next==null) {
			return head;
		}
		
		Node fst = head;
		Node sec = head;
		
		while (fst.next!=null&&fst.next.next!=null) {
			fst=fst.next.next;
			sec=sec.next;			
		}
		return sec;
	}
	
	//从尾到头打印单链表: reversePrintR(递归)
	public void reversePrintR(Node head) {
		if (head==null) {
			return;
		}
		
		reversePrintR(head.next);
		System.out.println(head.val);
	}
	
	//从尾到头打印单链表: reversePrintStack(利用栈,非递归遍历)
	public void reversePrintStack(Node head) {
		Stack<Node> myStack = new Stack<Node>();
		while (head!=null) {
			myStack.push(head);
			head=head.next;
			
		}
		
		while (!myStack.isEmpty()) {
			System.out.println(myStack.pop().val);
		}
	}
	
	//判断单链表是否有环,快慢指针
	public boolean hasCycle(Node head){
		boolean flag=false;
		if (head==null) {
			return flag;
		}
		Node slow = head.next;
		if (slow.next==null) {
			return flag;
		}
		Node fst = slow.next;
		while (slow!=null&&fst!=null) {	
			if (fst==slow) {
				flag=true;
				return flag;
			}
			
			slow=slow.next;
			fst=fst.next;
			if (fst!=null) {
				fst=fst.next;
			}			
		}
		return flag;
	}
	
	//快慢指针,找到有环链表中快慢指针第一次相遇的节点
	public Node meetingNode(Node head) {
		if (head==null) {
			return null;
		}
		Node slow = head.next;
		if (slow==null) {
			return null;
		}
		Node fast = slow.next;
		while (slow!=null && fast!=null) {
			if (slow==fast) {
				return fast;
			}
			
			slow=slow.next;
			fast=fast.next;
			if (fast!=null) {
				fast=fast.next;
			}
		}
		return null;
	}
	
	//求环的第一个入口节点
	public Node entryNodeOfLoop(Node head) {
		Node meetingNode = meetingNode(head);
		if (meetingNode==null) {
			return null;
		}
		
		int loopNodeNum=1;
		Node pNode1 = meetingNode;
		
		while (pNode1.next!=meetingNode) {
			pNode1=pNode1.next;
			++loopNodeNum;			
		}
		
		pNode1 = head;
		for (int i = 0; i < loopNodeNum; i++) {
			pNode1 = pNode1.next;
		}
		
		Node pNode2 = head; 
		while (pNode1!=pNode2) {
			pNode1=pNode1.next;
			pNode2=pNode2.next;
		}
		return pNode1;
	}
	
	//合并两条各自有序的单链表(递归)
	public Node mergeR(Node head1,Node head2){
		if (head1==null) {
			return head2;
		}else if (head2==null) {
			return head1;
		}
		
		Node mergeHead = null;
		
		if (head1.val<head2.val) {
			mergeHead=head1;
			mergeHead.next=mergeR(head1.next, head2);
		}else {
			mergeHead=head2;
			mergeHead.next=mergeR(head1, head2.next);
		}
		return mergeHead;
	}
	
	//两条单链表合并(非递归)
	public Node merge(Node head1,Node head2){
		if (head1==null) {
			return head2;
		}else if (head2==null) {
			return head1;
		}
				
		Node tmp = null;
		if (head1.val<head2.val) {
			 tmp=head1;
			 head1=head1.next;
		}else {
			tmp=head2;
			head2=head2.next;
		}
		
		Node mergeHead = tmp;
		
		while (head1!=null&&head2!=null) {
			if (head1.val<head2.val) {
				tmp.next=head1;
				head1=head1.next;
			}else {
				tmp.next=head2;
				head2=head2.next;
			}
			tmp=tmp.next;
		}
		
		if (head1!=null) {
			tmp.next=head1;
		}
		
		if (head2!=null) {
			tmp.next=head2;
		}
		return mergeHead;
	}
	
	
	//链表的插入排序
	//1、使用一个指针p指向未排好序的链表的第一个结点
	//2、在排序好的部分中找到找第一个大于等于q的前驱结点
	//3、将p对应的结点插入到正确位置,p重新指向未排好序的链表的第一个结点。直到链表完成排序好。 
	public Node insertSortList(Node head) {

		Node root = new Node(0); // 头结点
        root.next = head;
        Node p = head;
        Node q;
        Node r;

        while (p != null && p.next != null) {
            if (p.val <= p.next.val) {
                p = p.next;
            }else {
                q = p.next;
                p.next = q.next;

                r = root;
                // 找第一个大于等于q.val的前驱结点,因为在root.next到p之间必定存在这样的结点
                while (r.next.val <= q.val) {
                    r = r.next;
                }

                q.next = r.next;
                r.next = q;
            }
        }

        return root.next;
    }
	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
程序 = 数据结构 + 算法  程序是为了解决实际问题而存在的。然而为了解决问题,必定会使用到某些数据结构以及设计一个解决这种数据结构的算法。如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功。编程实战算法,不是念PPT,我们讲的就是实战与代码实现与企业应用。程序 = 数据结构 + 算法                ——图灵奖得主,计算机科学家N.Wirth(沃斯)作为程序员,我们做机器学习也好,做python开发也好,java开发也好。有一种对所有程序员无一例外的刚需 —— 算法与数据结构日常增删改查 + 粘贴复制 + 搜索引擎可以实现很多东西。同样,这样也是没有任何竞争力的。我们只可以粘贴复制相似度极高的功能,稍复杂的逻辑没有任何办法。语言有很多,开发框架更是日新月异3个月不学就落后我们可以学习很多语言,很多框架,但招聘不会考你用5种语言10种框架实现一个功能。真正让程序员有区分度,企业招聘万年不变的重点 —— 算法与数据结构。算法代表程序员水平的珠穆朗玛。如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功。 想写出精炼、优秀的代码,不通过不断的锤炼,是很难做到的。 开这个系列的目的是为了自我不断积累。不积跬步无以至千里嘛。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值