文章目录
链表
链表是一种有序列表.其中的各对象按线性顺序排列
数组的线性顺序是由数组下标决定的,而链表的顺序是由各个对象里的指针决定的
使用链表结果可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分使用计算机内存空间,灵活的内存动态管理,但是链表失去了数组随机读取的优点,同时链表由于增加了节点的指针域,空间开销比较大
链表作为一种基础的数据结构,可以用来生成其他类型的数据结构,可以分为单向链表,双向链表,循环链表
单向链表
单向链表是最简单的链表,它包含两个域,一个是信息域,一个是指针域,这个链接指向列表中的下一个节点,最后一个节点则指向一个空值

package com.zyd
object SinglyLinkedListDemo {
def main(args: Array[String]): Unit = {
val list = new SinglyLinkedList[Int]()
list.add(10)
list.add(20)
list.add(390)
list.printInfo()
list.delete(20)
list.add(35)
list.printInfo()
}
}
/**
* 单向链表
*
* @tparam T 列表中存储的元素的类型
*/
class SinglyLinkedList[T] {
//头结点
private var head: Node = _
//为了提高添加的效率,设置一个尾结点
private var tail: Node = _
def add(ele: T): Boolean = {
if (head == null) {
//第一次添加元素,则第一个结点置为head节点,尾结点和头节点一致
head = Node(ele, null)
tail = head
} else {
tail.next = Node(ele, null)
tail = tail.next // tail 指向新节点
}
true
}
def delete(ele: T): Boolean = {
//如果头节点为 null .表示没有元素,所有删除失败
if (head == null) return false
//如果头节点要删除,删除当前头节点,将下一个节点设置为头节点,删除的节点是同时也是尾节点,更新尾节点
if (head.value == ele) {
if (head.eq(tail)) { //比较是否为同一个对象,等价于java的比较地址值相等
tail = head.next
}
head = head.next
return true
} else {
//删除头节点不是要删除的节点,遍历后面的节点
var currentNode: Node = head
var nextNode = currentNode.next
while (nextNode != null) {
if (nextNode.value == ele) { //删除
currentNode.next = nextNode.next //让当前节点下一个节点的下一个节点
if (nextNode.eq(tail)) {
//当删除的节点是尾节点,尾节点需要指向当前节点
tail = currentNode
}
return true
}
currentNode = nextNode
nextNode = currentNode.next
}
}
false
}
def contain(ele: T): Boolean = {
if (head == null) return false
var tmp : Node = head
do {
if (tmp.value == ele) return true
tmp = tmp.next
} while (tmp != null)
false
}
/**
* 打印链表中的元素
*/
def printInfo(): Unit ={
if (head == null) return
var tmp : Node = head
do{
print(tmp.value + "-> ")
tmp = tmp.next
} while (tmp != null)
println()
}
case class Node(value: T, var next: Node)
}
10-> 20-> 390->
10-> 390-> 35->
双向链表
双向链表中不只有指向后一个节点的指针.还有指向前一个节点的指针,这样可以从任何一个节点访问前一个节点,或者后一个节点,甚至整个链表
对于需要大批量的另外储存数据在链表中的位置时候用

package com.zyd
object DoubleLinkedListDemo {
def main(args: Array[String]): Unit = {
val list = new DoubleLinkList[Int]()
list.add(1)
list.add(12)
list.add(134)
list.add(1455)
list.printInfo()
list.delete(1)
list.printInfo()
}
}
class DoubleLinkList[T] {
private var head: Node = _
private var tail: Node = _
def delete(ele: T): Boolean = {
//找到要删除的节点
val targetNode: Node = find(ele)
if (targetNode == null) { //删除节点不存在
false
} else {
val preNode = targetNode.pre //上一个节点
val nextNode = targetNode.next //下一个节点
if (targetNode == head) {
// 如果是头节点,下一个节点的pre指向null ,更新头节点
nextNode.pre = null
head = nextNode
} else if (targetNode == tail) {
preNode.next = null
tail = preNode
} else {
//这里体现指针双向性
preNode.next = nextNode
nextNode.pre = preNode
}
true
}
}
/**
* 找到要删除的节点
*
* @param ele
* @return
*/
private def find(ele: T): Node = {
var tmp: Node = head
while (tmp != null) {
if (tmp.value == ele) return tmp
tmp = tmp.next
}
null
}
def add(ele: T): Boolean = {
val newNode = Node(ele, null, null)
if (head == null) {
//第一次添加,上一个节点和下一个节点都应该是null
head = newNode
} else {
// 不是第一次添加,tail的next节点指向新节点,新节点
tail.next = newNode
newNode.pre = tail
}
tail = newNode
true
}
def printInfo(): Unit = {
if (head == null) return
var tmp: Node = head
do {
print(tmp.value + " -> ")
tmp = tmp.next
} while (tmp != null)
println()
}
case class Node(value: T, var pre: Node, var next: Node)
}
循环列表
package com.zyd
object CircularLinkedListDemo {
def main(args: Array[String]): Unit = {
val list = new CircularLinkedList[Int]()
list.add(1)
list.add(12)
list.add(134)
list.add(1455)
list.printInfo()
list.delete(1)
list.printInfo()
}
}
class CircularLinkedList[T] {
var head: Node = _
var tail: Node = _
var len = 0
def delete(ele: T): Boolean = {
//找到要删除的节点
val targetNode: Node = find(ele)
if (targetNode == null) { //删除节点不存在
false
} else {
val preNode = targetNode.pre //上一个节点
val nextNode = targetNode.next //下一个节点
if (targetNode == head) {
// 如果是头节点,下一个节点的pre指向null ,更新头节点
nextNode.pre = null
head = nextNode
} else if (targetNode == tail) {
preNode.next = null
tail = preNode
} else {
//这里体现指针双向性
preNode.next = nextNode
nextNode.pre = preNode
}
head.pre = tail
tail.next = head
len -= 1
true
}
}
/**
* 找到要删除的节点
*
* @param ele
* @return
*/
def find(ele: T): Node = {
var tmp: Node = head
while (tmp != null) {
if (tmp.value == ele) return tmp
//防止循环查找,已经到了尾节点,不再继续查找
if (tmp.eq(tail)) return null
tmp = tmp.next
}
null
}
def add(ele: T): Boolean = {
val newNode = Node(ele, null, null)
if (head == null) {
//第一次添加,上一个节点和下一个节点都应该是null
head = newNode
} else {
// 不是第一次添加,tail的next节点指向新节点,新节点
tail.next = newNode
newNode.pre = tail
}
tail = newNode
head.pre = tail
tail.next = head
len += 1
true
}
def printInfo(): Unit = {
if (head == null) return
var tmp: Node = head
do {
print(tmp.value + " -> ")
if (tmp.eq(tail)){
tmp = null
}else{
tmp = tmp.next
}
} while (tmp != null)
println()
}
case class Node(value: T, var pre: Node, var next: Node)
}
约瑟夫问题
使用循环列表解决
问题描述
设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直至剩下一个人为止
package com.zyd
object Josephu {
def main(args: Array[String]): Unit = {
println("开始: " + start(6, 2,4) + " 号 ")
}
/**
* * n 个人围一圈
* * 编号 k 的开始从 1 数
* * 数到 m 的那个人出圈
* *
* * @param n
* * @param k
* * @param m
*/
def start(n: Int, k: Int, m: Int) = {
val list = new CircularLinkedList[Int]
//初始化环形列表中n个人,编号从1 到 n
for (no <- 1 to n) {
list.add(no)
}
//找到开始数的节点的上一个节点(然后从下一个节点开始数1)
var startNode = list.find(k).pre
while (list.len != 1) {
for (num <- 1 to m) {
startNode = startNode.next
}
// 删除startNode 节点
list.delete(startNode.value)
print(startNode.value + " -> ")
// startNode 再置为上一个节点
startNode = startNode.pre
}
list.head.value
}
}
5 -> 3 -> 2 -> 4 -> 1 -> 开始: 6 号
















