链表是一种用于存储数据集合的数据结构。链表有以下属性:
链表抽象数据类型中的操作如下:
链表的主要操作
链表的辅助操作
? 整个数组所有的元素都存储在操作系统分配的一个内存块中。通过使用特定元素的索引作为数组下标,可以在常数时间内访问数组元素。
为什么能在常数时间内访问数组元素
数组的优点
数组的缺点
动态数组
链表的优点
链表的缺点
? 链表通常是指单向链表,它包含多个结点,每个结点有一个指向后继元素的next(下一个)指针。表中最后一个结点的next指针值为NULL,表示该链表的结束。
链表类型声明:
public class ListNode {
private int data;
private ListNode next;
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;
}
}
假设表头结点的指针指向链表中的第一个结点。遍历链表需完成以下步骤。
int ListLength(ListNode headNode) { //遍历然后返回链表长度
int length = 0;
ListNode currentNode = headNode;
while (currentNode != null){
length++;
currentNode = currentNode.getNext();
}
return length;
}
时间复杂度为O(n),用于扫描长度为n的链表。空间复杂度为0(1),仅用于创建临时变量。
单向链表的插入操作可分为以下3种情况:
在链表的表头前插入一个新结点(链表开始处)。
在链表的表尾后插入一个新结点(链表结尾处)。
在链表的中间插入一个新结点(随机位置)。
都可以归结为最后一种状态
实现方法新位指向前位的下一位,前位指向新位。
ListNode InsertInLinkedList(ListNode headNode,ListNode nodeToInsert,int position) {
if(headNode == null){//链表为空直接插入然后返回插入节点-因为java属性引用默认为空所以这里不用置null
return nodeToInsert;
}
int size = ListLength(headNode);
if(position > size+1 | position < 1){
System.out.println("插入位置错误!");
return headNode;
}
if(position == 1){//在链表开头插入将插入指向头然后将插入节点返回出去
nodeToInsert.setNext(headNode);
return nodeToInsert;
}else{//在除开始以外任意节点插入
ListNode previousNode = headNode;
int count = 1;
while (count < position-1){
previousNode = previousNode.getNext();
count++;
}
ListNode currentNode = previousNode.getNext();
nodeToInsert.setNext(currentNode);
previousNode.setNext(nodeToInsert);
}
return headNode;
}
ListNode DeleteNodeFromLinkedList(ListNode headNode,int position){
int size = ListLength(headNode);
if(position > size | position < 1){
System.out.println("删除位置错误!");
return headNode;
}
if(position == 1){
ListNode currentNode = headNode.getNext();
return currentNode;
}else{
ListNode previousNode = headNode;
int count = 1;
while (count < position){
previousNode = previousNode.getNext();
count++;
}
ListNode currentNode = previousNode.getNext();
previousNode.setNext(currentNode);
currentNode = null;
}
return headNode;
}
? 这个操作通过将当前结点存储在临时变量中然后释放当前结点(空间)的方式来完成。当释放完当前结点(空间)后,移动到下一个结点并将其存储在临时变量中,然后不断重复该过程直至释放所有结点。
void DeleteLinkedList(ListNode head){
ListNode auxilaryNode,iterator = head;
while (iterator != null){
auxilaryNode = iterator.getNext();
iterator = null;
iterator = auxilaryNode;
}
}
双向链表的优点是:
双向链表主要的缺点是:
public class DLLNode {
private int data;
private DLLNode next;
private DLLNode 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;
}
}
假设循环链表的类名为CLNode.循环列表的类结构可以为单向或者双向是一样的只是节点首尾相连
? 循环链表可以通过标记为表头的结点进行访问。为了统计结点个数,只能从标记为表头的结点开始遍历,利用虚拟结点--当前结点(current),当当前结点再次到达开始结点表头时结束计数过程。
? 如果链表为空,表头结点为NULL,在这种情况下设结点个数(count)等于0。否则,设置当前结点指向第一个结点(表头结点),然后遍历链表进行计数,直到当前结点达到开始结点。
int CircularListLength(CLLNode headNode){
int length =0;
CLLNode currentNode - headNode;
while (currentNode != null){
length++;
currentNode = currentNode.getNext();
if(currentNode == headNode)
break;
}
return length;
}
? 假设循环链表可以通过表头结点进行访问。
? 由于所有的结点采用循环方式排列,所以链表的表头结点的前驱结点就是表尾结点。
? 假设要输出从表头结点开始的结点的内容。
? 输出结点内容,移动到下一个结点,继续输出直至再次到达表头结点。
在由表头开始的循环链表的表尾插入一个包含数据(data)的结点。
新结点将放在表尾结点(即循环链表的最后一个结点)的后面,也就是说,在表尾结点和第一个结点之间插人该新结点
在循环链表的表头前插入结点与在表尾插入结点的唯一区别是,在插入新结点后,还需要更新指针。
删除循环链表中的最后一个结点
删除循环链表中的第一个结点
循环链表可用于管理计算机的计算资源,还可用于实现栈和队列。
具体定义:
原文:https://www.cnblogs.com/shitouzi-shi/p/14383462.html