我需要知道什么类型的算法在缓存机制的帮助下有效地计算树结构中的总和。
我想解决的问题很简单:有两种类型的节点:文件夹(F)和文件(L)......看起来像文件系统:) ...
可以在树结构中创建和移动文件夹和文件。文件大小不断变化。
现在我想要一个返回节点内容大小的函数size(node)
。
样品:
F1
- L1 : 10
- L2 : 33
F2
- F21
- F211
- L3 : 2
- L4 : 8
- F212
- F2121
- L5 : 18
- F2122
- L6 : 21
- L7 : 3
size(node) gives:
size(F1):43
size(F2):52
size(F21):52
size(F211):10
size(F212):42
size(L5):18
...
已知的解决方案是递归加起来:) ...
size(node)
int res=0;
if(node is File)
return sizeOfFile(node)
else
for each child of node
res += size(child)
end
end
return res
end
我问自己,我可以在这里使用某种类型的缓存。我需要搜索的算法的名称和类型是什么?
答案 0 :(得分:1)
你可以做一件事。您可以在访问节点并存储它时计算成本。认为这就像手机或电脑上的存储。这里的例子会更好。
我没有在这里给任何节点付出代价。假设您访问节点编号4.您通过添加成本6和7来计算成本并将其存储在数据库中。在数据库上,这可以像directory path -- cost
一样存储。现在假设您要计算成本2.您不需要访问4,因为您已经预先计算了成本。您只需要计算5的成本,然后就完成了。因此,我们将数据库中的成本5和2存储起来。下次如果你想知道4或5的大小,你可以从数据库中获取它。
我假设这是一个文件结构。所以你需要更频繁地去目录。您访问的越多,将完成更多的尺寸存储。计算成本越容易。最后,如果您更改文件或移动它们,只需计算该节点的成本。
我认为这里的优点是每次访问节点时都不需要计算成本。你将使用一个存储空间,随着时间的推移,你可以更快地计算尺寸。
希望它有意义。
答案 1 :(得分:0)
附加了使用swift和核心数据的实现。它的作用是在核心数据/ sqlite数据库中生成随机树数据,并将一些节点(文件夹)移动到其他目标文件夹中。输出看起来像这样:
Building the tree ...
insert file nodes: [0(15): 1 100]
insert file nodes: [1(15): 101 200]
insert file nodes: [2(15): 201 300]
insert file nodes: [3(15): 301 400]
insert file nodes: [4(15): 401 500]
insert file nodes: [5(15): 501 600]
insert file nodes: [6(15): 601 700]
insert file nodes: [7(15): 701 800]
insert file nodes: [8(15): 801 900]
insert file nodes: [9(15): 901 1000]
insert file nodes: [10(15): 1001 1100]
insert file nodes: [11(15): 1101 1200]
insert file nodes: [12(15): 1201 1300]
insert file nodes: [13(15): 1301 1400]
insert file nodes: [14(15): 1401 1500]
Congratulations! Tree exists. It's initial size is:75563
Moving F000120 to target folder F000103 ...
before moving:
size[F000120] = 607 path = /F000001/F000003/
source folder: size[F000003] = 37388
target folder: size[F000103] = 1134
after moving:
size[F000120] = 607 path = /F000001/F000003/F000014/F000030/F000072/F000103/
source folder: size[F000003] = 37995
target folder: size[F000103] = 1741
Moving F000200 to target folder F000209 ...
before moving:
size[F000200] = 224 path = /F000001/F000016/
source folder: size[F000016] = 1686
target folder: size[F000209] = 215
after moving:
size[F000200] = 224 path = /F000001/F000002/F000006/F000007/F000041/F000209/
source folder: size[F000016] = 1462
target folder: size[F000209] = 439
Moving the nodes completed. Tree size is:75563
核心数据模型是:
AppDelegate
:
//
// AppDelegate.swift
// SizesNTrees
//
// Created by Markus Schmid on 20.02.16.
//
import UIKit
import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: NSURL = {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1]
}()
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = NSBundle.mainBundle().URLForResource("SizesNTrees", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SizesNTrees.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch {
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
let nserror = error as NSError
NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}
}
}
}
ViewController
:
//
// ViewController.swift
// SizesNTrees
//
// Created by Markus Schmid on 20.02.16.
//
import UIKit
import CoreData
enum NodeType: Int {
case File
case Folder
}
var node : Node!
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let root=nodeWithName("F000001") {
print("Tree exists. Initial tree size is:\(root.size!)")
}
else {
print("Building the tree ...")
buildTree(300, noFiles:1500)
}
if let root=nodeWithName("F000001") {
print("Congratulations! Tree exists. It's initial size is:\(root.size!)")
moveNode("F000120",targetFolderName:"F000103")
moveNode("F000200",targetFolderName:"F000209")
print("Moving the nodes completed. Tree size is:\(root.size!)")
}
else {
print("Tree is missing.")
return
}
do {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func moveNode(nodeName:String, targetFolderName:String) {
// try to move move nodeName to targetFolderName
if let node=nodeWithName(nodeName) {
if let targetFolder=nodeWithName(targetFolderName) {
print ("Moving \(nodeName) to target folder \(targetFolderName) ... ")
print("before moving:")
print(" size[\(node.name!)] = \(node.size!) path = \(path(node))")
let origParent=node.parent
print(" source folder: size[\(origParent!.name!)] = \(origParent!.size!)")
print(" target folder: size[\(targetFolder.name!)] = \(targetFolder.size!)")
if !isDescendantOrSelf(targetFolder, ascendant: node) {
move(node, toFolder: targetFolder)
print("after moving:")
print(" size[\(node.name!)] = \(node.size!) path = \(path(node))")
print(" source folder: size[\(origParent!.name!)] = \(origParent!.size!)")
print(" target folder: size[\(targetFolder.name!)] = \(targetFolder.size!)")
}
else {
print ("Moving folder to target folder failed! Target folder is descendant from folder.")
}
}
else {
print ("Target folder \(targetFolderName) not found!")
}
}
else {
print ("Node \(nodeName) not found!")
}
}
func buildTree(noFolders:Int,noFiles:Int) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let nodeEntity = NSEntityDescription.entityForName("Node", inManagedObjectContext:managedContext)
// create folders
autoreleasepool {
for index in 1...noFolders {
node = NSManagedObject(entity: nodeEntity!, insertIntoManagedObjectContext: managedContext) as! Node
node.name=String(format: "F%06d", index)
node.size=0
node.type=NodeType.Folder.rawValue
node.nr=index
if index>1 {
node.parent=nodeOfType(NodeType.Folder.rawValue, nr:Int(arc4random_uniform(UInt32(index-1))+1))
}
}
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
managedContext.reset()
}
// create files
let bSize = 100
let noB = noFiles/bSize
var index = 0
for var bNr=0;(bNr<noB || ((bNr*bSize<noFiles) && (((bNr+1)*bSize)>noFiles)) );bNr++ {
autoreleasepool {
var startIndex=0
var maxIndex=0
if bNr<noB {
startIndex=bNr*bSize+1
maxIndex=(bNr+1)*bSize
}
else {
startIndex=bNr*bSize+1
maxIndex=noFiles
}
print("insert file nodes: [\(bNr)(\(noB)): \(startIndex) \(maxIndex)]")
for index=startIndex;index<maxIndex+1;index++ {
let node = NSManagedObject(entity: nodeEntity!, insertIntoManagedObjectContext: managedContext) as! Node
node.name=String(format: "L%06d", index)
node.size=Int(arc4random_uniform(100)+1)
node.type=NodeType.File.rawValue
node.nr=index
node.parent=self.nodeOfType(NodeType.Folder.rawValue, nr:Int(arc4random_uniform(UInt32(noFolders))+1))
}
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
managedContext.reset()
}
}
fillSize();
}
func nodeWithName(name:String, context:NSManagedObjectContext) -> Node? {
var node : Node?
let managedContext = context
let predicate = NSPredicate(format:"name = %@", name)
let request = NSFetchRequest(entityName:"Node")
request.predicate=predicate
do {
let fetchedNodes = try managedContext.executeFetchRequest(request) as! [Node]
if fetchedNodes.count>0 {
node=fetchedNodes[0]
}
else {
node=nil
}
} catch {
fatalError("Failed to fetch nodes: \(error)")
}
return node
}
func nodeOfType(type:NSNumber, nr:NSNumber, context:NSManagedObjectContext) -> Node? {
var node : Node?
let managedContext = context
let predicate = NSPredicate(format:"type = %@ AND nr = %@", type, nr)
let request = NSFetchRequest(entityName:"Node")
request.predicate=predicate
do {
let fetchedNodes = try managedContext.executeFetchRequest(request) as! [Node]
if fetchedNodes.count>0 {
node=fetchedNodes[0]
}
else {
node=nil
}
} catch {
fatalError("Failed to fetch nodes: \(error)")
}
return node
}
func nodeWithName(name:String) -> Node? {
var node : Node?
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let predicate = NSPredicate(format:"name = %@", name)
let request = NSFetchRequest(entityName:"Node")
request.predicate=predicate
do {
let fetchedNodes = try managedContext.executeFetchRequest(request) as! [Node]
if fetchedNodes.count>0 {
node=fetchedNodes[0]
}
else {
node=nil
}
} catch {
fatalError("Failed to fetch nodes: \(error)")
}
return node
}
func nodeOfType(type:NSNumber, nr:NSNumber) -> Node? {
var node : Node?
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let predicate = NSPredicate(format:"type = %@ AND nr = %@", type, nr)
let request = NSFetchRequest(entityName:"Node")
request.predicate=predicate
do {
let fetchedNodes = try managedContext.executeFetchRequest(request) as! [Node]
if fetchedNodes.count>0 {
node=fetchedNodes[0]
}
else {
node=nil
}
} catch {
fatalError("Failed to fetch nodes: \(error)")
}
return node
}
func fillSize() {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let predicate = NSPredicate(format:"type = 1")
let request = NSFetchRequest(entityName:"Node")
request.predicate=predicate
do {
let fetchedNodes = try managedContext.executeFetchRequest(request) as! [Node]
for node in fetchedNodes {
node.size=size(node);
}
} catch {
fatalError("Failed to fetch nodes: \(error)")
}
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
func size(node:Node) -> Int {
var res : Int = 0
if node.type == 0 {
res=(node.size?.integerValue)!;
}
else {
if let nodeChilds=node.childs {
for child in nodeChilds {
res = res + size(child);
}
}
}
return res;
}
func path(node:Node) -> String {
if let parent=node.parent {
return path(parent).stringByAppendingString((node.parent?.name)!).stringByAppendingString("/")
}
else {
return "/"
}
}
func move(node:Node, toFolder:Node) -> Bool {
var success=false
if let size=node.size {
if let parent=node.parent {
if parent.isEqual(toFolder) {
return true
}
else {
propagateSizeChange(-size.integerValue, parent: parent)
}
}
propagateSizeChange(size.integerValue, parent: toFolder)
node.parent=toFolder
success=true
}
return success
}
func setSizeFor(file:Node, var newSize:Int) {
if newSize<=0 {
newSize=0
}
if let size=node.size {
if let parent=node.parent {
propagateSizeChange(newSize-size.integerValue, parent: parent)
}
}
}
func isDescendantOrSelf(node:Node, ascendant:Node) -> Bool {
var success=false
if ascendant.isEqual(node) {
return true
}
else {
if let nodeChilds=ascendant.childs {
if nodeChilds.contains(node) {
return true;
}
else {
for child in nodeChilds {
success = (success || self.isDescendantOrSelf(node,ascendant:child))
if success {
break;
}
}
}
}
}
return success
}
func propagateSizeChange(value:Int, parent:Node) {
if parent.type == 1 {
parent.size = NSNumber(integer:(parent.size!.integerValue + value))
if let parent=parent.parent {
parent.size = NSNumber(integer:(parent.size!.integerValue + value))
propagateSizeChange(value, parent: parent)
}
}
}
}