java版数据结构——单链表的实现

talk is cheap show me the code.接下来将展示单链表的数据结构的实现。代码实现的功能主要是插入和删除,这也是单链表的核心思想操作,操作指针。

package com.chenli.LinkedList;
/**
 * 定义结点
 * @author 陈力
 *
 */
public class Node {

	public Object data;//数据域
	public Node next;//指针域
	
	//构造方法
	public Node(Object obj){
		this.data = obj;
		next = null;
	}
	
	/**
	 * 打印方法
	 */
	
	public void print(){
		System.out.println(data + " ");
	}
}

定义结点。

package com.chenli.LinkedList;
/**
 * 单链表实现插入删除功能
 * @author 陈力
 *
 */
@SuppressWarnings("all")
public class LinkedList {

	private int size = 0;//记录链表的长度
	private Node head;//定义头指针(记住是头指针,不是头结点。理解为头指针比较方便理解我的代码)

	//初始化链表
	public LinkedList(){
		this.head = null;
	}
	
	//链表的长度
	public int length(){
		return size;
	}
	
	//判断链表是否为空
	public boolean isEmpty(){
		return size == 0;
	}
	
	//头结点插入元素
	public void insertFirst(Object obj){
		Node newNode = new Node(obj);//生成要添加的新结点
		if(head == null){//头指针为空
			head = newNode;//让头指针指向新结点
			size++;
		}else{
			newNode.next = head;//头指针指向的值赋值给新结点指针指向的值。
			head = newNode;//让头指针指向新结点。
			size++;
		}		
	}
	
	//尾结点插入元素
	public void insertLast(Object obj){
		Node temp = head;//定义一个移动指针
		Node newNode = new Node(obj);//生成新的要添加的结点
		if(temp == null){//一开始指向头指针,头指针为空的情况。
			temp = newNode;//头指针指向新的值
			size++;
		}else{
			while(temp.next != null){//遍历链表
				temp = temp.next;//移动指针的操作
			}
			temp.next = newNode;//遍历到最后一个结点的指针域是为空的,然后把最后一个的指针指向新的结点,就实现了尾部添加了。
			size++;
		}
	}
	
	//指定序号插入元素
	public void insert(int index,Object obj){
		Node newNode = new Node(obj);//生成要添加的结点
		Node temp = head;//定义一个移动指针
		int i = 1;//定义一个变量,记录位置
		if(index<1 || index>length()+1){//判断插入位置是否合理
			System.out.println("插入位置不合理");
		}
		while(temp.next!=null){//遍历链表
			if(index == i++){//找到要添加元素的位置
				/**
				 * temp:指的是当前位置的前一个结点
				 * temp.next:指的是当前位置
				 * temp.next.next:指的是当前位置的后一个结点
				 */
				newNode.next = temp.next;
				temp.next = newNode;
				size++;
				return;
			}
			temp = temp.next;//移动指针的操作
		}
	}
	
	//头结点删除
	public Object removeFirst(){
		
		Node temp = head;//移动指针
		if(temp == null){//头指针为空的情况
			System.out.println("这是一个空链表");
		}else{
			Node removeNode = temp;//头指针不为空,指向的结点即为第一个结点,也就是删除结点。定义这个变量是为存储删除的值
			temp = temp.next;//指针移动,指向删除结点的后一个结点
			head = temp;//把头指针指向删除结点的后一个结点
			size--;
			return removeNode.data;//把删除结点的值返回
		}
		return null;
	}
	
	//尾结点删除
	public Object removeLast(){
		Node temp = head;//定义一个临时指针,先指向头指针	
		if(temp == null){//头指针
			System.out.println("这是一个空链表");
		}else{
			Node currentNode = temp.next;//定义一个当前指针,把它作为移动指针。
			while(currentNode.next != null){//循环遍历指针
				temp = currentNode;//临时指针指向当前指针,即存储当前结点的值。
				currentNode = currentNode.next;//当前指针的移动
			}
			temp.next = null;//到了这里,说明当前currentNode.next==null的,即currentNode是没有后继结点了,而他就是要被删除的结点。把它前一个结点的指针域赋值为空,不指向它,那它不就删除了。
			size--;
			return currentNode.data;//把删除结点的值返回
		}
		return null;
	}
	
	//删除指定的序号的结点
	public Object remove(int index){
		Node temp = head;//定义临时指针
		if(temp == null){//头指针为空
			System.out.println("这是一个空链表");
		}else{
			Node currentNode = temp.next;//定义一个当前指针的变量
			int i = 1;//定义一个记录位置的变量
			if(index<1 || index>length()+1){
				System.out.println("删除位置不合理");
			}
			while(currentNode.next!=null){
				if(index == i++){
					temp = currentNode;//把当前结点的值即要删除的结点存储到temp临时指针中。目的是要把它存储的值返回回来。
					currentNode = currentNode.next;
					size--;
					return temp.data;
				}
				currentNode = currentNode.next;
			}
		}
		
		return null;
		
	}
	
	//打印链表
	public void print(){
		Node temp = head;
		while(temp != null){
			temp.print();
			temp = temp.next;
		}
	}
	
}

头指针:链表中第一个结点存储的位置。
头指针与头结点的异同点:
头指针是必要元素,而头结点并非是必要元素。头结点的引入是为插入与删除结点的统一。

单链表的时间复杂度
查找的时间复杂度为O(n)
插入和删除的时间复杂度为O(1)

接下来扩展一下单链表的其他链表,这些链表都是在单链表的基础上实现的。
循环链表
定义:将单链表的终端结点的指针指向头结点。
循环链表和单链表的主要差异在于循环判断条件上,单链表判断p->next不等于空,循环链表判断p->next不等于头结点。

双向链表
定义:定义一个前指针和后指针,前指针指向前驱,后指针指向后驱。
*prior是前指针
*next是后指针
p是结点
p->next->prior = p = p->prior->next

插入赋值操作的顺序很重要:
这是来自《大话数据结构》的图
删除操作
这是来自《大话数据结构》的图

猜你喜欢

转载自blog.csdn.net/weixin_42870497/article/details/86749890