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
插入赋值操作的顺序很重要:
删除操作