内功之--链表

  1. 单链表

  • 链表内存存储
 头指针地址data域next域
head150110a2180
  120  
  130a4

 

170

 

  140a6null
  150a1110
  180a3130

 

 

 

 

 

 

 

 

 

总结:1.链表是以节点的方式存储的,是链式存储。

           2.各个节点不一定连续

          3.链表分带头结点的链表和不带头节点的链表

          4.每个节点包含data域,next域:指向下一个节点

  • 实例

单链表基本操作

代码:

/** 
 * Project Name:leetcode 
 * File Name:SingleLinkedList.java 
 * Package Name:singlelinkedList 
 * Date:2020年2月5日下午4:18:04 
 * Copyright (c) 2020, chenzhou1025@126.com All Rights Reserved. 
 * 
*/

package singlelinkedList;

import java.util.Stack;

/**
 * ClassName:SingleLinkedList <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2020年2月5日 下午4:18:04 <br/>
 * 
 * @author yrz
 * @version
 * @see
 */
public class SingleLinkedListDemo {
	public static void main(String[] args) {
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		Node node1 = new Node(1, "宋江", "及时雨");
		Node node2 = new Node(2, "吴用", "智多星");
		Node node3 = new Node(3, "卢俊义", "玉麒麟");
		Node node4 = new Node(4, "林冲", "豹子头");

//		singleLinkedList.add(node1);
//		singleLinkedList.add(node4);
//		singleLinkedList.add(node3);
//		singleLinkedList.add(node2);

		singleLinkedList.addByOrder(node1);
		singleLinkedList.addByOrder(node2);
		singleLinkedList.addByOrder(node3);
		singleLinkedList.addByOrder(node4);
		singleLinkedList.List();
		System.out.println();
//		Node node5 = new Node(3, "鲁智深", "花和尚");
//		singleLinkedList.update(node5);
//		singleLinkedList.List();
//		System.out.println();
//		singleLinkedList.delete(node5);
//		singleLinkedList.List();
//		int res = SingleLinkedListDemo.getLength(singleLinkedList.getHeadNode());
//		System.out.println("res=" + res);
//
//		System.out.println();

		// 找到倒数第key个节点
//		Node indexNode = SingleLinkedListDemo.getNodeInfo(singleLinkedList.getHeadNode(), 1);
//
//		System.out.println(indexNode);

		// 反转链表
//		System.out.println();
//		SingleLinkedListDemo.reverseSingLinkedList(singleLinkedList.getHeadNode());
//
//		singleLinkedList.List();
		//倒序输出链表
		System.out.println("-------------");
		SingleLinkedListDemo.reverseprint(singleLinkedList.getHeadNode());
	}

	// 获取单链表有效个数

	public static int getLength(Node headNode) {
		// 链表为空,返回0
		if (headNode.next == null) {
			return 0;
		}

		Node temp = headNode;// 临时指针变量,用于遍历链表节点使用。
		int count = 0;// 记录有效节点的变量
		while (true) {
			if (temp.next != null) {
				count++;
				temp = temp.next;
			} else {
				break;
			}
		}

		return count;
	}

	// 获取倒数第K个节点信息
	public static Node getNodeInfo(Node headNode, int index) {
		// 空链表
		if (headNode.next == null) {
			return null;
		}
		// 获取链表大小
		int size = 0;
		Node temp = headNode;
		size = SingleLinkedListDemo.getLength(headNode);
		// index校验
		if (index < 0 || index > size) {
			return null;
		}
		// 找到倒数倒数第k个节点位置
		for (int i = 0; i <= size - index; i++) {
			temp = temp.next;
		}
		return temp;
	}

	// 单链表反转

	public static void reverseSingLinkedList(Node headNode) {
		if (headNode.next == null) {
			return;
		}
		Node temp = headNode;
		Node curNextNode = null;// 当前节点的下一个节点
		Node reverseNode = new Node(0, "", "");

		while (temp.next != null) {

			curNextNode = temp.next.next;// 当前有效节点的下一个节点
			temp.next.next = reverseNode.next;// 新链表的头节点的下一个节点给反转链表头节点的下一个节点
			reverseNode.next = temp.next;// 反转链表头节点和新节点连接
			temp.next = curNextNode;// 指针后移

		}

		headNode.next = reverseNode.next;
	}

	// 从尾到头打印单链表(使用栈)
	public static void reverseprint(Node headNode) {
		if (headNode.next == null) {
			return ;
		}
		Node temp = headNode;
		Stack<Node> stack = new Stack<Node>();
		while (temp.next != null) {
				stack.add(temp.next);
				temp = temp.next;
		}
		
		while(stack.size()>0) {
			System.out.println(stack.pop());
		}
	
	}

}

//创建链表
class SingleLinkedList {
	// 初始化头节点
	Node headNode = new Node(0, "", "");

	public Node getHeadNode() {
		return headNode;
	}

	// 直接添加链表尾部
	public void add(Node node) {
		Node temp = headNode;// 指针变量,从头节点开始遍历
		while (true) {
			// 判断是不是链表尾部
			if (temp.next == null) {
				break;
			}
			// temp后移
			temp = temp.next;
		}
		// 此时指针指向最后一个节点,节点的next指向新节点。添加元素完成
		temp.next = node;
	}

	// 添加节点时,根据no将英雄插入指定位置
	public void addByOrder(Node node) {
		boolean flag = false;// 用于判断添加节点是否重复
		Node temp = headNode;
		while (true) {
			// 判断是否是链表尾部,是的话直接添加
			if (temp.next == null) {
				break;
			}
			// 判断添加节点是否重复
			if (temp.next.no == node.no) {
				flag = true;
				break;
			}
			// 判断插入位置
			if (temp.next.no > node.no) {
				break;
			}
			// 指针后移
			temp = temp.next;
		}

		if (flag) {
			System.out.println("当前添加节点已存在,编号是" + node.no);
		} else {
			// 插入新节点
			node.next = temp.next;
			temp.next = node;
		}

	}

	// 修改节点
	public void update(Node node) {
		Node temp = headNode;
		boolean flag = false;
		while (true) {
			// 判断链表是否为空
//			if (temp.next == null) {
//				break;
//			}
			// 找到要修改的节点
			if (temp.no == node.no) {
				flag = true;
				break;
			}
			// 指针后移
			temp = temp.next;
		}

		if (flag) {
			temp.name = node.name;
			temp.nickname = node.nickname;
		}
	}

	// 删除指定节点
	public void delete(Node node) {
		Node temp = headNode;
		boolean flag = false;
		while (true) {
			// 链表最后,退出
			if (temp.next == null) {
				break;
			}
			// 找到要删除的节点的前一个节点
			if (node.no == temp.next.no) {
				flag = true;
				break;
			}
			temp = temp.next;
		}

		if (flag) {
			temp.next = temp.next.next;
		} else {
			System.out.printf("要删除的%d节点不存在\n", node.no);
		}

	}

	// 遍历链表
	public void List() {
		Node temp = headNode;
		while (true) {
			// 判断链表是否为空
			if (temp.next != null) {
				System.out.println(temp.next.toString());
				temp = temp.next;
			} else {
				break;
			}

		}
	}
}

//创建节点
class Node {
	int no;
	String name;
	String nickname;
	Node next;

	public Node(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}

	@Override
	public String toString() {
		return "Node [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}

}
  • 面试题

     一.  获取单链表有效个数

// 获取倒数第K个节点信息
	public static Node getNodeInfo(Node headNode, int index) {
		// 空链表
		if (headNode.next == null) {
			return null;
		}
		// 获取链表大小
		int size = 0;
		Node temp = headNode;
		size = SingleLinkedListDemo.getLength(headNode);
		// index校验
		if (index < 0 || index > size) {
			return null;
		}
		// 找到倒数倒数第k个节点位置
		for (int i = 0; i <= size - index; i++) {
			temp = temp.next;
		}
		return temp;
	}


       二. 单链表反转

       思路分析:

// 单链表反转

	public static void reverseSingLinkedList(Node headNode) {
		if (headNode.next == null) {
			return;
		}
		Node temp = headNode;
		Node curNextNode = null;// 当前节点的下一个节点
		Node reverseNode = new Node(0, "", "");

		while (temp.next != null) {

			curNextNode = temp.next.next;// 当前有效节点的下一个节点
			temp.next.next = reverseNode.next;// 新链表的头节点的下一个节点给反转链表头节点的下一个节点
			reverseNode.next = temp.next;// 反转链表头节点和新节点连接
			temp.next = curNextNode;// 指针后移

		}

		headNode.next = reverseNode.next;
	}

       三. 从尾到头打印单链表(使用栈)

// 从尾到头打印单链表(使用栈)
	public static void reverseprint(Node headNode) {
		if (headNode.next == null) {
			return ;
		}
		Node temp = headNode;
		Stack<Node> stack = new Stack<Node>();
		while (temp.next != null) {
				stack.add(temp.next);
				temp = temp.next;
		}
		
		while(stack.size()>0) {
			System.out.println(stack.pop());
		}
	
	}

2.双链表

  • 单向链表的缺点 

        查找方向只有一个,双向链表可以向前或者向后查找

       双向链表可以可以自行删除节点,单向节点不能自动删除,需要辅助节点

双向链表基本操作:

思路

 

代码实现:

/** 
 * Project Name:leetcode 
 * File Name:DoubleLinkedList.java 
 * Package Name:singlelinkedList 
 * Date:2020年2月7日上午11:36:36 
 * Copyright (c) 2020, chenzhou1025@126.com All Rights Reserved. 
 * 
*/

package singlelinkedList;

/**
 * ClassName:DoubleLinkedList <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2020年2月7日 上午11:36:36 <br/>
 * 
 * @author yrz
 * @version
 * @see
 */
public class DoubleLinkedListDemo {
	public static void main(String[] args) {
		DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
		Node2 node1 = new Node2(1, "宋江", "及时雨");
		Node2 node2 = new Node2(2, "吴用", "智多星");
		Node2 node3 = new Node2(3, "卢俊义", "玉麒麟");
		Node2 node6 = new Node2(6, "林冲", "豹子头");

		doubleLinkedList.addData(node1);
		doubleLinkedList.addData(node2);
		doubleLinkedList.addData(node3);
		doubleLinkedList.addData(node6);
		doubleLinkedList.List();
		System.out.println();

		Node2 node4 = new Node2(4, "鲁智深", "花和尚");

		doubleLinkedList.addByOrder(node4);
		doubleLinkedList.List();
		System.out.println();

		// 删除节点
		doubleLinkedList.deleteNode(6);
		doubleLinkedList.List();

		// 修改节点信息
		System.out.println();
		doubleLinkedList.update(new Node2(4, "xxx", "ccc"));
		doubleLinkedList.List();

	}
}

//双向链表
class DoubleLinkedList {
	// 初始化头节点
	Node2 headNode = new Node2(0, "", "");

	public Node2 getHeadNode() {
		return headNode;
	}

	// 添加节点到链表尾部

	public void addData(Node2 node) {
		Node2 temp = headNode;
		while (true) {
			// 判断是否是链表尾部,是的话直接添加
			if (temp.next == null) {
				break;
			} else {
				temp = temp.next;
			}
		}

		temp.next = node;
		node.pre = temp;
	}

	// 添加按顺序插入节点
	public void addByOrder(Node2 node) {
		boolean flag = false;// 用于判断添加节点是否重复
		Node2 temp = headNode;
		while (true) {
			// 判断是否是链表尾部,是的话直接添加
			if (temp.next == null) {
				break;
			}
			// 判断添加节点是否重复
			if (temp.next.no == node.no) {
				flag = true;
				break;
			}
			// 判断插入位置
			if (temp.next.no > node.no) {
				break;
			}
			// 指针后移
			temp = temp.next;
		}

		if (flag) {
			System.out.println("当前添加节点已存在,编号是" + node.no);
		} else {
			// 插入新节点
			// 插入节点和后一个节点连接
			temp.next.pre = node;
			node.next = temp.next;
			// 插入节点和前一个节点连接
			temp.next = node;
			node.pre = temp;
		}

	}

	// 删除节点
	public void deleteNode(int no) {
		Node2 temp = headNode;
		boolean flag = false;
		while (true) {
			// 链表最后,退出
			if (temp.next == null) {
				break;
			}
			// 找到要删除的节点的前一个节点
			if (no == temp.next.no) {
				flag = true;
				break;
			}
			temp = temp.next;
		}

		if (flag) {
			//最后一个节点,释放指针
			if (temp.next.next != null) {
				//后继元素的前驱指向前一个元素
				temp.next.next.pre = temp.next.pre;
			}
			//前驱元素的后继指向后继元素
			temp.next.pre.next = temp.next.next;

			// temp.next = temp.next.next;
		} else {
			System.out.printf("要删除的%d节点不存在\n", no);
		}

	}

	// 修改节点
	public void update(Node2 node) {
		Node2 temp = headNode;
		boolean flag = false;
		while (true) {
			// 判断链表是否为空
//				if (temp.next == null) {
//					break;
//				}
			// 找到要修改的节点
			if (temp.no == node.no) {
				flag = true;
				break;
			}
			// 指针后移
			temp = temp.next;
		}

		if (flag) {
			temp.name = node.name;
			temp.nickname = node.nickname;
		}
	}

	// 遍历链表
	public void List() {
		Node2 temp = headNode;
		while (true) {
			// 判断链表是否为空
			if (temp.next != null) {
				System.out.println(temp.next.toString());
				temp = temp.next;
			} else {
				break;
			}

		}
	}

}

//创建节点
class Node2 {
	int no;
	String name;
	String nickname;
	Node2 next;// 后继节点
	Node2 pre;// 前驱节点

	public Node2(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}

	@Override
	public String toString() {
		return "Node [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}

}

3.循环链表

  • Josephu约瑟夫问题

思路:

1.创建一个环形链表来表示这个圈:

2.出队列

 

代码实现:

/** 
 * Project Name:leetcode 
 * File Name:Josephu.java 
 * Package Name:singlelinkedList 
 * Date:2020年2月8日下午10:07:05 
 * Copyright (c) 2020, chenzhou1025@126.com All Rights Reserved. 
 * 
*/

package singlelinkedList;

/**
 * ClassName:Josephu <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2020年2月8日 下午10:07:05 <br/>
 * 
 * @author yrz
 * @version
 * @see
 */
public class Josephu {

	public static void main(String[] args) {
		CircularLinkedList circularLinkedList = new CircularLinkedList();
		circularLinkedList.add(15);
		circularLinkedList.List();
		System.out.println();
		circularLinkedList.countNode(1, 2, 15);
	}
}

//创建循环链表
class CircularLinkedList {
	//第一个节点
	Node3 first = null;

	// 添加节点
	public void add(int nums) {
		// 校验nums
		if (nums < 1) {
			return;
		}
		// 辅助指针
		Node3 temp = null;

		for (int i = 1; i <= nums; i++) {
			// 第一个节点
			Node3 node = new Node3(i);
			if (i == 1) {
				first = node;
				first.setNext(node);// 构成环
				temp = first;
			} else {
				temp.setNext(node);// 指向下一个节点
				node.setNext(first);// 构成环
				temp = node;// 指针后移
			}
		}

	}

	/**
	 * 出环
	 * @author Administrator 
	 * @param startNo--从第几个开始
	 * @param count--数几下
	 * @param nums --一共几个节点
	 * @since JDK 1.6
	 */
	public void countNode(int startNo, int count, int nums) {
		Node3 temp = first;
		// 校验数据
		if (startNo < 1 || count > nums) {
			System.out.println("数据错误");
			return;
		}
		// 事先指向链表最后一个节点
		while (true) {
			if (temp.getNext() == first) {
				break;
			}

			temp = temp.getNext();
		}
		// 报数前,将first和temp移动startNo-1次
		for (int i = 0; i < startNo - 1; i++) {
			first = first.getNext();
			temp = temp.getNext();
		}
		// 报数时,将first和temp移动count-1次
		while (true) {
			if (temp == first) {
				break;
			}
			for (int i = 0; i < count - 1; i++) {
				first = first.getNext();
				temp = temp.getNext();
			}

			// 出圈
			System.out.printf("出圈小孩编号%d\n", first.getNo());
			first = first.next;
			temp.next = first;
		}

		System.out.printf("最后一个出圈小孩编号%d\n", first.getNo());
	}

	// 遍历链表
	public void List() {
		Node3 temp = first;
		while (true) {
			System.out.printf("编号%d\n", temp.getNo());
			if (temp.next == first) {
				break;
			}
			temp = temp.next;
		}

	}
}

//创建节点
class Node3 {
	int no;
	Node3 next;

	public Node3(int no) {
		this.no = no;
	}

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public Node3 getNext() {
		return next;
	}

	public void setNext(Node3 next) {
		this.next = next;
	}

}

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值