前言
最近在编程时觉得自己在数据结构与算法上有很大不足急需弥补一下,决定总该写点东西了。便复习了一下链表的基础知识,在这里分享一下自己的心得。
概述
单链表是一种基础的数据结构,虽然在平时的开发中较少用到,但我个人而言,学习单链表是从数据结构入门的一个好开端,毕竟是比较简单,而且在算法代码的练习中,总能不知不觉地感受到指针与内存地址的存在。
链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构。链表由一系列的节点组成,节点动态生成。在单链表中,单个节点由存储元素的数据域与指向下一个节点地址的指针组成。
对单链表的操作即建立在对链表中节点的指针操作。(在这里只演示不带哨兵模式情况下的单链表)
节点例:(python为例子):
class SinglyNode:
def __init__(self, value=0, next=None):
self.value = value #数据域
self.next = next #指向下一个节点地址的指针
def __str__(self):
return str(self.value)
public class SinglyNode {
private Object value;//数据域
private Object next;//指向下一个节点地址的指针
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public Object getNext() {
return next;
}
public void setNext(Object next) {
this.next = next;
}
}
单链表例子:
class SinglyLinkedList:
#头结点指针
head = None
如上代码,一个单链表最基础的是一个头结点
基础操作
1.获取单链表长度
核心思想即不断遍历链表节点,每切换一个节点即链表长度+1
def getLinkLength(self):
curent = self.head
count = 0
while curent != None:
count += 1
curent = curent.next
return count
2.获取尾部一个节点
核心思想即遍历到最后一个节点时,将该节点返回即可
def getLastNode(self):
if not self.head: #当链表为空时
return None # 链表为空,返回 None
current = self.head
while current.next:
current = current.next
return current
3.获取指定下标的节点
核心思想用一个整数作为计数器来确定要返回的节点
def getIndexNode(self,index):
if self.head == None: #当链表为空时
return None # 链表为空,返回 None
point = self.head
count = 0
while point != None:
if count == index:
return point
point = point.next
count += 1
raise IndexError("数组越界")
4.头插法和尾插法插入数据
实际上,头插法在各种插入的的方式中是最高的了,尾插法即找到最后的节点,然后将该节点的指针指向待插入的节点
#以头插法向单链表中插入数据
def addFirstNode(self, node):
if self.head is None:
self.head = node
else:
node.next = self.head
self.head = node
#尾部插入节点
def addLastNode(self, node=None):
point = self.getLastNode() #获取最后位置的节点
if point is None:
raise IndexError("链表为空")
point.next=node
5.插入节点
通过计数器来确定插入的位置
def insert(self, index, node):
length = self.getLinkLength()
if not self.head: #当链表为空时
return None # 链表为空,返回 None
if index == 0:
self.addFirstNode(node)
return
pre = self.head
count = 0
while pre != None:
if count == index-1:
break
pre = pre.next
count += 1
next=pre.next #下一跳的节点
node.next = next
pre.next = node
return True
6.删除头结点和尾结点
#删除头结点
def removeFirstNode(self):
curent = self.head.next
self.head.next = None
self.head = curent
#删除尾部节点
def removeLastNode(self):
if self.head is None:
return False
length = self.getLinkLength()
if length == 1:
self.head = None
return True
pre = self.getIndexNode((length-2))
pre.next = None
7.删除节点
找到下标节点,删除该节点
#删除某个节点
def remove(self,index):
length = self.getLinkLength()
if length == 0 or length-1 < index:
raise ValueError("长度越界了")
if index == 0:
self.removeFirstNode() #删除头结点
if index == length-1: #最后的恶一个节点
self.removeLastNode()
pre = self.getIndexNode(index-1)
curent = pre.next
next = pre.next.next
curent.next = None
pre.next = next
8.得到链表的数组
在这里得到的数组使用的地址不是原链表的节点对象地址,即互不影响
#遍历链表得到对象数组
def loop(self):
nodeNums = []
point = self.head
while point != None:
nodeNums.append(SinglyNode(point.value))
point = point.next
return nodeNums
常见算法
1.单链表倒序
核心思想就是桑连续的指针prevr,curent,next,从头到尾循环将指针调转方向
def reversalList(self):
length = self.getLinkLength()
if length == 0 or length == 1:
return
prver = None
current = self.head
while current is not None:
nextNode = current.next
# 将当前节点的下一个节点指向前一个
current.next = prver
prver = current
current = nextNode
self.head = prver
2.删除特定的值
核心思想就是两个一前一后的指针p,q。p在后面记录位置,q在前面探测是否可以删除
def removeNode(self,node):
if self.head is None:
raise ValueError("链表为NUll")
if self.head.value == node.value:
if self.head.next != None:
next = self.head.next
self.head.next = None
self.head = next
else:
self.head = None
#给p,q赋予初始位置
p = self.head
q = self.head.next
# 只要q不为None即一直往后走
while q != None:
if q.value == node.value: #当q就是要删除的位置时
q = q.next
p.next.next = None
p.next = q
else:
q = q.next
p = p.next
# 完成
3.删除倒数的节点
即从后面开始数的节点开始删除,比如1就删除最后一个,2就是删除倒数第二个,可以使用递归的方式去探找最后一个节点
def removeNthFromEndRecursion(self,index,point,preve):
if index < 1:
return
current = point
#判断是不是最后尾部的节点
if current.next == None:
if index == 1:
preve.next = None
return 1
else:
result = self.removeNthFromEndRecursion(index,current.next,current)
if result+1 == index:
if preve == None:#当删除的是第一个节点时走这个逻辑
self.head = point.next
point.next = None
else:
point = point.next
preve.next.next = None
preve.next = point
return result+1