如何用 Java 手写一个单链表

实现的功能

在这里插入图片描述

Process.java

package linkList;
import java.util.Scanner;

public class Process {

	public static void main(String[] args) {

		Scanner in =new Scanner(System.in);
		LinkedList linkedList = new LinkedList();
		System.out.println("链表功能测试:");
		while(true){
			System.out.println("1、显示链表:");
			System.out.println("2、追加节点:");
			System.out.println("3、更新节点:");
			System.out.println("4、插入节点:");
			System.out.println("5、删除节点:");
			System.out.println("6、链表长度:");
			System.out.println("7、反向查找:");
			System.out.println("8、反转链表:");
			System.out.println("9、逆序打印:");
			System.out.println("0、退出程序:");
			System.out.println("输入功能编号:");
			int func = in.nextInt();
			switch (func) {
				case 1:
					linkedList.list();
					break;
				case 2:
					System.out.println("依次输入节点编号,节点名称:");
					int no = in.nextInt();
					String name = in.next();
					Node node = new Node(no,name);
					linkedList.append(node);
					break;
				case 3:
					System.out.println("输入节点编号:");
					int no3 = in.nextInt();
					System.out.println("输入节点名称:");
					String name3 = in.next();
					Node node3 = new Node(no3,name3);
					linkedList.update(node3);
					break;
				case 4:
					System.out.println("依次输入节点编号,节点名称:");
					int no4 = in.nextInt();
					String name4 = in.next();
					Node node4 = new Node(no4,name4);
					linkedList.insert(node4);
					break;
				case 5:
					System.out.println("输入节点编号:");
					int no5 = in.nextInt();
					linkedList.delete(no5);
					break;
				case 6:
					System.out.println("链表中有效节点个数:"+linkedList.getLength());
					break;
				case 7:
					System.out.println("输入要查找的倒数位数:");
					int index = in.nextInt();
					linkedList.getLast(index);
					break;
				case 8:
					linkedList.reverseList();
					break;
				case 9:
					linkedList.reversePrint();
					break;
				case 0:
					System.out.println("退出!");
					System.exit(0);
					break;
			}

		}
	}
}

Node.java

package linkList;
public class Node{
	public int no; // 节点编号
	public String name; // 节点名称
	public Node next; // 下一个节点的引用

	// 构造器
	public Node(int no,String name){
		this.no = no;
		this.name = name;
	}

	// 重写toString方法
	@Override
	public String toString() {
		return "Node{" +
				"no=" + no +
				", name=" + name +
				'}';
	}
}

LinkedList.java

package linkList;

import java.net.Socket;
import java.util.Stack;

public class LinkedList {

	// 初始化头节点
	private Node head = new Node(0,"头节点");

	public Node getHead(){
		return this.head;
	}
	//  添加节点到单向链表
	public void append(Node node){
		// 定义临时节点
		Node tempNode = head;
		while(true){
			// 找到链表的最后
			if(tempNode.next == null){
				break;
			}
			// 如果没有到最后,将tempNode后移
			tempNode = tempNode.next;
		}
		// 当退出while循环时,tempNode就指向了链表的最后
		// 将最后这个节点的next,指向 新的节点
		tempNode.next = node;
	}
	// 遍历显示链表
	public void list(){
		// 判断链表是否为空
		if(head.next == null){
			System.out.println("链表为空");
			return;
		}
		// 定义临时节点
		Node tempNode = head.next;
		while (true){
			// 判断是否到链表最后
			if(tempNode == null ){
				break;
			}
			//  输出节点的信息
			System.out.println(tempNode);
			tempNode = tempNode.next;
		}
	}
	public void insert(Node node){

		// 定义临时节点
		Node tempNode = head;
		boolean flag = false;
		while(true){
			if(tempNode.next == null){
				break;
			}
			if(tempNode.next.no > node.no){
				break;
			}else if (tempNode.next.no == node.no){
				flag = true;
			}
			tempNode = tempNode.next;
		}
		if(flag){
			System.out.println(node.no+"不能添加,已存在");
		}else{
			node.next = tempNode.next;
			tempNode.next = node;
		}
	}
	public void update(Node node){

		// 判断是否为空
		if(head.next == null){
			System.out.println("链表为空-");
			return;
		}
		// 根据编号,找到需要修改的节点
		Node tempNode = head.next;
		boolean flag = false; // 表示是否找到该节点
		while(true){
			if(tempNode == null){
				break; // 已经遍历完链表
			}
			if(tempNode.no == node.no){
				flag = true;
				break;
			}
			tempNode = tempNode.next;
		}
		// 根据flag 判断是否找到要修改的节点
		if(flag){
			tempNode.name = node.name;
		}else{
			System.out.println("没有找到编号为"+node.no+"的节点");
		}
	}
	public void delete(int no){
		Node tempNode = head;
		boolean flag = false;
		while(true) {
			if (tempNode.next == null) {
				break;
			}
			if(tempNode.next.no == no){

				// 找到待删除节点的前一个节点
				flag = true;
				break;
			}
			tempNode = tempNode.next;
		}
		if(flag){
			tempNode.next = tempNode.next.next;
		}else {
			System.out.println("要删除的节点"+no+"不存在");
		}
	}
	// 查找链表中的有效个数
	//1. 编写一个方法,接收 head 节点,同时接收一个 index
	//2. index 表示是倒数第 index 个节点
	//3. 先把链表从头到尾遍历,得到链表的总的长度 getLength
	//4. 得到 size 后,我们从链表的第一个开始遍历 (size-index)个,就可以得到
	//5. 如果找到了,则返回该节点,否则返回 null
	public int getLength(){
		Node tempNode = head.next;
		if (tempNode == null){
			return 0;
		}
		int len = 0;
		while(tempNode != null){
			len++;
			tempNode = tempNode.next;
		}
		return len;
	}
	// 反向查找 查找链表中倒数第n个
	public void getLast(int index){
		int length = this.getLength();
		if(head.next == null){
			System.out.println("链表为空:");
			return;
		}
		if(index>length || index <= 0){
			System.out.println("该节点不存在:");
			return;
		}
		Node tempNode = head.next;
		for(int i=0;i<length - index;i++){
			tempNode = tempNode.next;
		}
		System.out.println(tempNode);
	}
	// 单链表的反转
	public void reverseList(){
		Node tempHead = new Node(0,"临时头节点");
		tempHead.next = null;
		//如果当前链表为空,或者只有一个节点,无需反转,直接返回
		if(head.next == null || head.next.next == null){
			this.list();
			return;
		}
		//遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表 reverseHead 的最前端
		Node currentNode = head.next;
		while (currentNode != null){
			Node tempNext = currentNode.next;
			currentNode.next = tempHead.next;
			tempHead.next = currentNode;//下一个节点指向新的链表的最前端
			currentNode = tempNext;
		}
		head.next = tempHead.next;
	}
	// 单链表的逆序打印
	public void reversePrint(){
		if(head.next == null){
			System.out.println("链表为空");
		}
		//创建要给一个栈,将各个节点压入栈
		Stack<Node> socket = new Stack<Node>();
		Node currentNode = head.next;
		//将栈中的节点进行打印,pop 出栈
		while(currentNode != null){
			socket.push(currentNode);
			currentNode = currentNode.next;
		}
		while (socket.size() > 0){
			System.out.println(socket.pop());
		}
	}
}

双向链表的实现思路

  • 遍历方向和单链表一样,只是可以向前,也可以向后查找
  • 添加 (默认添加到双向链表的最后)
    • (1) 先找到双向链表的最后这个节点
    • (2) temp.next = newHeroNode
    • (3) newHeroNode.pre = temp;
  • 修改 思路和 原来的单向链表一样.
  • 删除
    • 因为是双向链表,因此,我们可以实现自我删除某个节点
    • 直接找到要删除的这个节点,比如 temp
    • temp.pre.next = temp.next
    • temp.next.pre = temp.pre;

在这里插入图片描述

发布了117 篇原创文章 · 获赞 222 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_43901693/article/details/101114386
今日推荐