数据结构-链表 JAVA语言实现
作为一名Android程序员,开始学习数据结构和算法,用JAVA语言写写自己对链表的看法和代码上的实现,如果有问题,麻烦指出,互相学习。
目录
- 单向链表
- 双向链表
- 循环链表
1、单向链表
单向链表包含多个结点,每个结点都有一个next指向下一个结点,直到最后一个结点的next指向为null,链表结束。
单向链表结点实体类:
/**
* 单向链表
*/
public class ListNode {
private int data; //结点的数据
private ListNode next; //指向下一个结点
public ListNode(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
1.1 遍历链表
循环遍历每个结点,知道结点的next为null时,当前结点为尾结点。
/**
* 遍历链表,获取长度
* @param headNode
* @return 链表长度
*/
public int listLength(ListNode headNode){
int count = 0;
ListNode currentNode = headNode;
while(currentNode != null){
count ++;
currentNode = currentNode.getNext();
}
return count ;
}
1.2 插入元素
插入元素包括三种情况:
- 插入到头结点前
- 插入到链表中间位置
插入到尾结点
(1)插入到头结点只需要将插入的结点的next指向当前头结点,返回插入结点即可。
(2)插入到中间或者尾结点,遍历结点直到插入位置的前一个节点,将next指向插入结点,再将插入结点的next指向后一元素(如果插入的结点在最后,后以节点为null)。
/**
* 插入结点 可以为头 中 尾插入
* @param headNode 当前头结点
* @param insertNode 插入结点
* @param position 插入位置
* @return 返回插入后的头结点
*/
public ListNode insertNode(ListNode headNode,ListNode insertNode,int position){
//当当前链表为空,新链表直接为插入的链表
if(headNode == null){
return insertNode;
}
//获取长度
int size = listLength(headNode);
if(position > size + 1 || position < 1){
//插入位置不合法
System.out.println("插入位置不合法!");
return headNode;
}
//链表开头插入
if(position == 1){
insertNode.setNext(headNode);
headNode = insertNode;
}else{
ListNode previousNode = headNode;
int count = 1;
while (count < position -1){
previousNode = previousNode.getNext();
count++;
}
insertNode.setNext(previousNode.getNext());
previousNode.setNext(insertNode);
}
return headNode;
}
1.3 删除元素
删除元素同样区别删除位置:头、中、尾
(1)删除头结点:将头结点next设为null,下一个结点即为新的头结点
(2)删除中间或尾部结点,遍历链表直到删除的位置的前一个结点,同时拿到删除位置的后一个结点,将前一个结点的next指向后一个节点。
/**
* 删除某个结点
* @param headNode 头结点
* @param position 删除位置
* @return 返回头结点
*/
public ListNode deleteNode(ListNode headNode,int position){
//当前链表为空,
if(headNode == null){
System.out.print("当前链表为空,不能删除!");
return null;
}
//获取长度
int size = listLength(headNode);
if(position > size || position < 1){
//删除位置不合法
System.out.println("删除位置不合法!");
return headNode;
}
if (position == 1){
// 删除头结点
ListNode currentNode = headNode.getNext();
headNode = null;
return currentNode;
}else {
ListNode previousNode = headNode;
int count = 1;
while (count < position - 1){
previousNode = previousNode.getNext();
count++;
}
//currentNode为删除的那个结点
ListNode currentNode = previousNode.getNext();
previousNode.setNext(currentNode.getNext());
currentNode = null;
}
return headNode;
}
2、双向链表
双向链表顾名思义就是有两个方向,多一个前驱结点。
双向链表结点的实体类:
/**
* 双向链表
*/
public class DLLNode {
private int data;
private DLLNode next;
private DLLNode previous;
public DLLNode(int data, DLLNode newxt, DLLNode previous) {
this.data = data;
this.next = newxt;
this.previous = previous;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public DLLNode getNext() {
return next;
}
public void setNext(DLLNode next) {
this.next = next;
}
public DLLNode getPrevious() {
return previous;
}
public void setPrevious(DLLNode previous) {
this.previous = previous;
}
}
2.1 遍历元素
与单向链表类似,直接上代码:
/**
* 获取双向链表长度
* @param headNode 头结点
* @return
*/
public int getDllLength(DLLNode headNode) {
int count = 0;
DLLNode current = headNode;
while (current != null) {
current = current.getNext();
count++;
}
return count;
}
2.2 插入元素
与单向链表相似,但是要修改插入元素指向的前驱结点。
/**
* 插入结点
* @param headNode 当前头结点
* @param insertNode 插入的结点
* @param position 插入位置
* @return 插入后的头结点
*/
public DLLNode insertDllNode(DLLNode headNode , DLLNode insertNode, int position){
if (headNode == null){
return insertNode;
}
int size = getDllLength(headNode);
if(position < 1 || position > size + 1){
System.out.println("插入位置有误");
return headNode;
}
//插入到首位
if (position == 1){
insertNode.setNext(headNode);
headNode.setPrevious(insertNode);
return insertNode;
}else {
DLLNode previousNode = headNode;
int count = 1;
while (count < position - 1){
previousNode = previousNode.getNext();
count ++;
}
DLLNode currentNode = previousNode.getNext();
if(previousNode.getNext() != null){
//插入的位置在末尾
currentNode.setPrevious(insertNode);
}
insertNode.setNext(currentNode);
previousNode.setNext(insertNode);
insertNode.setPrevious(previousNode);
}
return headNode;
}
2.3 删除元素
/**
* 删除结点
* @param headNode 头结点
* @param position 插入位置
* @return 新链表的头结点
*/
public DLLNode deleteNode(DLLNode headNode , int position){
if(headNode == null){
System.out.println("当前链表为空,不能进行删除操作!");
return null;
}
int size = getDllLength(headNode);
if(position < 1 || position > size){
System.out.println("删除位置有误");
return headNode;
}
if(position == 1){
DLLNode currentNode = headNode.getNext();
currentNode.setPrevious(null);
headNode = null;
return currentNode;
}else {
DLLNode currentNode = headNode;
int count = 1;
while (count < position){
currentNode = currentNode.getNext();
count++;
}
DLLNode previousNode = currentNode.getPrevious();
DLLNode nextNode = currentNode.getNext();
previousNode.setNext(nextNode);
if(nextNode != null){
nextNode.setPrevious(previousNode);
}
currentNode = null;
}
return headNode;
}
3、循环链表
循环链表与单向、双向链表的很大差别是没有null值表示结束,不做判断的话,一直循环下去。
循环链表结点实体类:
/**
* 循环链表
*/
public class CLLNode {
private int data;
private CLLNode next;
public CLLNode(int data) {
this.data = data;
}
public CLLNode(int data, CLLNode next) {
this.data = data;
this.next = next;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public CLLNode getNext() {
return next;
}
public void setNext(CLLNode next) {
this.next = next;
}
}
3.1 遍历链表
通过判断循环后的结点是否为头结点还做出结束循环操作。
/**
* 循环链表长度
*
* @param headNode 头结点
* @return 长度
*/
public int getListLenth(CLLNode headNode) {
int count = 0;
CLLNode currentNode = headNode;
while (currentNode != null) {
currentNode = currentNode.getNext();
count++;
if (currentNode == headNode) {
break;
}
}
return count;
}
3.2 插入元素
循环链表插入与单向链表类似,注意将尾结点指向头结点即可。
/**
* 尾部插入
*
* @param headNode 头结点
* @param insertNode 插入结点
* @return 返回头结点
*/
public CLLNode insertEndNode(CLLNode headNode, CLLNode insertNode) {
CLLNode currentNode = headNode;
while (currentNode.getNext() != headNode) {
currentNode = currentNode.getNext();
}
currentNode.setNext(insertNode);
insertNode.setNext(headNode);
return headNode;
}
/**
* 头部插入
* @param headNode 头结点
* @param insertNode 插入结点
* @return 返回头结点
*/
public CLLNode insertStartNode(CLLNode headNode, CLLNode insertNode) {
CLLNode currentNode;
currentNode = headNode;
while (currentNode.getNext() != headNode) {
currentNode = currentNode.getNext();
}
currentNode.setNext(insertNode);
insertNode.setNext(headNode);
return insertNode;
}
3.3 删除元素
/**
* 删除头结点
*
* @param headNode 头结点
* @return 新头结点
*/
public CLLNode deleteStartNode(CLLNode headNode) {
CLLNode currentNode = headNode;
while (currentNode.getNext() != headNode) {
currentNode = currentNode.getNext();
}
CLLNode newHeadNode = headNode.getNext();
currentNode.setNext(newHeadNode);
return newHeadNode;
}
/**
* 删除尾结点
*
* @param headNode 头结点
* @return 新头结点
*/
public CLLNode deleteEndNode(CLLNode headNode) {
CLLNode currentNode = headNode;
CLLNode lastNode = headNode;
while (currentNode.getNext() != headNode) {
lastNode = currentNode;
currentNode = currentNode.getNext();
}
currentNode = null;
lastNode.setNext(headNode);
return headNode;
}
循环链表中部的删除、插入于单向链表相似。