サーチ…


前書き

アルゴリズムはコンピューティングのバックボーンです。どちらの状況でどのアルゴリズムを使用するかを選択することで、良いプログラマーと平均を区別できます。そのことを念頭に置いて、そこにはいくつかの基本的なアルゴリズムの定義とコード例があります。

挿入ソート

挿入ソートは、コンピュータサイエンスのより基本的なアルゴリズムの1つです。挿入ソートは、コレクションを反復処理して要素をランク付けし、その値に基づいて要素を配置します。セットはソートされた半分とソートされていない半分に分割され、すべての要素がソートされるまで繰り返されます。挿入ソートにはO(n2)の複雑さがあります。下の例のように拡張子に入れることも、そのためのメソッドを作成することもできます。

extension Array where Element: Comparable {

func insertionSort() -> Array<Element> {
    
    //check for trivial case
    guard self.count > 1 else {
        return self
    }
    
    //mutated copy
    var output: Array<Element> = self
    
    for primaryindex in 0..<output.count {
        
        let key = output[primaryindex]
        var secondaryindex = primaryindex
        
        while secondaryindex > -1 {
            if key < output[secondaryindex] {
                
                //move to correct position
                output.remove(at: secondaryindex + 1)
                output.insert(key, at: secondaryindex)
            }
            secondaryindex -= 1
        }
    }
    
    return output
}
}

並べ替え

バブルソート

これはソートされるリストを繰り返しステップ実行し、隣り合ったアイテムの各ペアを比較し、間違った順序でスワップする単純なソートアルゴリズムです。リストの通過は、スワップが不要になるまで繰り返されます。アルゴリズムは単純ですが、ほとんどの問題では遅すぎて実用的ではありません。それはO(n2)の複雑さを有するが、挿入ソートよりも遅いと考えられる。

extension Array where Element: Comparable {

func bubbleSort() -> Array<Element> {
    
    //check for trivial case
    guard self.count > 1 else {
        return self
    }
    
    //mutated copy
    var output: Array<Element> = self
    
    for primaryIndex in 0..<self.count {
        let passes = (output.count - 1) - primaryIndex
        
        //"half-open" range operator
        for secondaryIndex in 0..<passes {
            let key = output[secondaryIndex]
            
            //compare / swap positions
            if (key > output[secondaryIndex + 1]) {
                swap(&output[secondaryIndex], &output[secondaryIndex + 1])
            }
        }
    }
    
    return output
}

}

挿入ソート

挿入ソートは、コンピュータサイエンスのより基本的なアルゴリズムの1つです。挿入ソートは、コレクションを反復処理して要素をランク付けし、その値に基づいて要素を配置します。セットはソートされた半分とソートされていない半分に分割され、すべての要素がソートされるまで繰り返されます。挿入ソートにはO(n2)の複雑さがあります。下の例のように拡張子に入れることも、そのためのメソッドを作成することもできます。

extension Array where Element: Comparable {

func insertionSort() -> Array<Element> {
    
    //check for trivial case
    guard self.count > 1 else {
        return self
    }
    
    //mutated copy
    var output: Array<Element> = self
    
    for primaryindex in 0..<output.count {
        
        let key = output[primaryindex]
        var secondaryindex = primaryindex
        
        while secondaryindex > -1 {
            if key < output[secondaryindex] {
                
                //move to correct position
                output.remove(at: secondaryindex + 1)
                output.insert(key, at: secondaryindex)
            }
            secondaryindex -= 1
        }
    }
    
    return output
}
}

選択ソート

選択ソートはその単純さのために示されています。配列の最初の要素から始まり、最小値(またはソート順に応じて最大値)として値が保存されます。その後、配列全体を繰り返し、最小値を他の値よりも小さく置き換えます。その最小値が配列の左端部に配置され、次のインデックスから配列の最後までプロセスが繰り返されます。選択ソートはO(n2)の複雑さを持っていますが、それは対応するものよりも遅いと考えられます - 選択ソート。

func selectionSort() - > Array {//自明なケースのガードを調べるself.count> 1 else {return self}

//mutated copy
var output: Array<Element> = self
 
for primaryindex in 0..<output.count {
    var minimum = primaryindex
    var secondaryindex = primaryindex + 1
     
    while secondaryindex < output.count {
        //store lowest value as minimum
        if output[minimum] > output[secondaryindex] {
            minimum = secondaryindex
        }
        secondaryindex += 1
    }
     
    //swap minimum value with array iteration
    if primaryindex != minimum {
        swap(&output[primaryindex], &output[minimum])
    }
}
 
return output 
}

クイックソート - O(n log n)の複雑さの時間

Quicksortは高度なアルゴリズムの1つです。時間複雑度がO(n log n)であり、除算&征服戦略が適用されます。この組合せにより、高度なアルゴリズム性能が得られる。クイックソートは、まず大きいアレイを2つの小さなサブアレイ、すなわち低エレメントと高エレメントに分割します。 Quicksortは、サブアレイを再帰的にソートすることができます。

手順は次のとおりです。

ピボットと呼ばれる要素を配列から選択します。

ピボットよりも小さい値を持つすべての要素がピボットの前に来るように配列の順序を変更し、ピボットよりも大きな値を持つすべての要素がその後ろに来るようにします(等しい値はいずれかの方向に進むことができます)。この分割後、ピボットは最終位置にあります。これはパーティション操作と呼ばれます。

上記のステップを小さな値の要素のサブ配列に、より大きな値の要素のサブ配列に個別に繰り返し適用します。

mutating func quickSort() - > Array {

func qSort(start startIndex: Int, _ pivot: Int) {
    
    if (startIndex < pivot) {
        let iPivot = qPartition(start: startIndex, pivot)
        qSort(start: startIndex, iPivot - 1)
        qSort(start: iPivot + 1, pivot)
    }
}
qSort(start: 0, self.endIndex - 1)
return self
}

mutating func qPartition(start startIndex: Int, _ pivot: Int) -> Int {

var wallIndex: Int = startIndex

//compare range with pivot
for currentIndex in wallIndex..<pivot {
    
    if self[currentIndex] <= self[pivot] {
        if wallIndex != currentIndex {
            swap(&self[currentIndex], &self[wallIndex])
        }
        
        //advance wall
        wallIndex += 1
    }
}
    //move pivot to final position
    if wallIndex != pivot {
        swap(&self[wallIndex], &self[pivot])
    }
    return wallIndex
}

選択ソート

選択ソートはその単純さのために示されています。配列の最初の要素から始まり、最小値(またはソート順に応じて最大値)として値が保存されます。その後、配列全体を繰り返し、最小値を他の値よりも小さく置き換えます。その最小値が配列の左端部に配置され、次のインデックスから配列の最後までプロセスが繰り返されます。選択ソートはO(n2)の複雑さを持っていますが、それは対応するものよりも遅いと考えられます - 選択ソート。

func selectionSort() -> Array<Element> {
    //check for trivial case
    guard self.count > 1 else {
        return self
    }
     
    //mutated copy
    var output: Array<Element> = self
     
    for primaryindex in 0..<output.count {
        var minimum = primaryindex
        var secondaryindex = primaryindex + 1
         
        while secondaryindex < output.count {
            //store lowest value as minimum
            if output[minimum] > output[secondaryindex] {
                minimum = secondaryindex
            }
            secondaryindex += 1
        }
         
        //swap minimum value with array iteration
        if primaryindex != minimum {
            swap(&output[primaryindex], &output[minimum])
        }
    }
     
    return output
}

漸近分析

私たちにはさまざまなアルゴリズムが用意されているので、配列をソートしたいときは、どちらを行うかを知る必要があります。したがって、アルゴリズムの速度と信頼性を測定する方法が必要です。それは漸近分析が始まるところです。漸近分析は、入力サイズ(n)が増加するにつれアルゴリズムの効率を記述するプロセスです。コンピュータ科学では、asymptoticsは通常Big O Notationと呼ばれる一般的な形式で表現されます。

  • 線形時間O(n) :関数が目的を達成するために配列の各項目を評価する必要がある場合、要素の数が増えるにつれ関数の効率が低下することを意味します。 このような関数は、その速度が入力サイズに依存するため、線形時間で実行されると言われています。
  • 多項式時間O(n2) :関数の複雑さが指数関数的に増加する場合(関数の配列のn要素がn乗の2乗であることを意味する)、その関数は多項式時間で動作します。これらは通常、ネストされたループを持つ関数です。 2つのネストされたループはO(n2)の複雑さをもたらし、3つのネストされたループはO(n3)の複雑さをもたらす。
  • 対数時間O(log n):対数時間関数の複雑さは、入力(n)のサイズが大きくなると最小になります。これらはプログラマーが目指す機能のタイプです。

クイックソート - O(n log n)の複雑さの時間

Quicksortは高度なアルゴリズムの1つです。時間複雑度がO(n log n)であり、除算&征服戦略が適用されます。この組合せにより、高度なアルゴリズム性能が得られる。クイックソートは、まず大きいアレイを2つの小さなサブアレイ、すなわち低エレメントと高エレメントに分割します。 Quicksortは、サブアレイを再帰的にソートすることができます。

手順は次のとおりです。

  1. ピボットと呼ばれる要素を配列から選択します。

  2. ピボットよりも小さい値を持つすべての要素がピボットの前に来るように配列の順序を変更し、ピボットよりも大きな値を持つすべての要素がその後ろに来るようにします(等しい値はいずれかの方向に進むことができます)。この分割後、ピボットは最終位置にあります。これはパーティション操作と呼ばれます。

  3. 上記のステップを小さな値の要素のサブ配列に、より大きな値の要素のサブ配列に個別に繰り返し適用します。

    mutating func quickSort() -> Array<Element> {
    
    func qSort(start startIndex: Int, _ pivot: Int) {
        
        if (startIndex < pivot) {
            let iPivot = qPartition(start: startIndex, pivot)
            qSort(start: startIndex, iPivot - 1)
            qSort(start: iPivot + 1, pivot)
        }
    }
    qSort(start: 0, self.endIndex - 1)
    return self
    

    }

    mutation func qPartition(start startIndex:Int、_ pivot:Int) - > Int {

    var wallIndex: Int = startIndex
    
    //compare range with pivot
    for currentIndex in wallIndex..<pivot {
        
        if self[currentIndex] <= self[pivot] {
            if wallIndex != currentIndex {
                swap(&self[currentIndex], &self[wallIndex])
            }
            
            //advance wall
            wallIndex += 1
        }
    }
    
    //move pivot to final position
    if wallIndex != pivot {
        swap(&self[wallIndex], &self[pivot])
    }
    return wallIndex
}

グラフ、トライ、スタック

グラフ

コンピュータサイエンスでは、グラフは、無向グラフと数学からの有向グラフの概念を実装するための抽象データ型です。グラフデータ構造は、無向グラフまたは有向グラフのための順序付けられたペアのためのこれらの頂点の順序付けられていないペアのセットと共に、有限の(およびおそらく可変の)頂点またはノードまたはポイントのセットからなる。これらのペアは、無向グラフのエッジ、アーク、または線、有向グラフの矢印、有向辺、有向弧、または有向線として知られています。頂点は、グラフ構造の一部であってもよく、または整数インデックスまたは参照によって表される外部エンティティであってもよい。グラフデータ構造はまた、シンボリックラベルまたは数値属性(コスト、容量、長さなど)など、いくつかのエッジ値を各エッジに関連付けることができる。 (ウィキペディア、 ソース

//
//  GraphFactory.swift
//  SwiftStructures
//
//  Created by Wayne Bishop on 6/7/14.
//  Copyright (c) 2014 Arbutus Software Inc. All rights reserved.
//
import Foundation


public class SwiftGraph {
   
    
    //declare a default directed graph canvas
    private var canvas: Array<Vertex>
    public var isDirected: Bool
    
    
    init() {
        canvas = Array<Vertex>()
        isDirected = true
    }
    
    
    //create a new vertex
    func addVertex(key: String) -> Vertex {
        
        
        //set the key
        let childVertex: Vertex = Vertex()
        childVertex.key = key
        
        
        //add the vertex to the graph canvas
        canvas.append(childVertex)
        
        
        return childVertex
    }
    
    
    
    //add edge to source vertex
    func addEdge(source: Vertex, neighbor: Vertex, weight: Int) {
        
        
        //create a new edge
        let newEdge = Edge()
        
        
        //establish the default properties
        newEdge.neighbor = neighbor
        newEdge.weight = weight
        source.neighbors.append(newEdge)
        
        
        print("The neighbor of vertex: \(source.key as String!) is \(neighbor.key as String!)..")
        
        
        //check condition for an undirected graph
        if isDirected == false {
            
            
           //create a new reversed edge
           let reverseEdge = Edge()
            
            
           //establish the reversed properties
           reverseEdge.neighbor = source
           reverseEdge.weight = weight
           neighbor.neighbors.append(reverseEdge)
            
           print("The neighbor of vertex: \(neighbor.key as String!) is \(source.key as String!)..")
            
        }
        
        
    }

    
    
    
    
    /* reverse the sequence of paths given the shortest path.
       process analagous to reversing a linked list. */

    func reversePath(_ head: Path!, source: Vertex) -> Path! {
        
        
        guard head != nil else {
            return head
        }
        
        //mutated copy
        var output = head
        
        
        var current: Path! = output
        var prev: Path!
        var next: Path!
        
        
        while(current != nil) {
            next = current.previous
            current.previous = prev
            prev = current
            current = next
        }
        
        
        //append the source path to the sequence
        let sourcePath: Path = Path()
        
        sourcePath.destination = source
        sourcePath.previous = prev
        sourcePath.total = nil
        
        output = sourcePath
        
        
        return output
        
    }

    
    
    
    //process Dijkstra's shortest path algorthim
    func processDijkstra(_ source: Vertex, destination: Vertex) -> Path? {
        
        
        var frontier: Array<Path> = Array<Path>()
        var finalPaths: Array<Path> = Array<Path>()
        
        
        //use source edges to create the frontier
        for e in source.neighbors {
            
            let newPath: Path = Path()
            
            
            newPath.destination = e.neighbor
            newPath.previous = nil
            newPath.total = e.weight
            
            
            //add the new path to the frontier
            frontier.append(newPath)
            
        }
        

        //construct the best path
        var bestPath: Path = Path()
        
        
        while frontier.count != 0 {
            
            //support path changes using the greedy approach
            bestPath = Path()
            var pathIndex: Int = 0

            
            for x in 0..<frontier.count {
               
                let itemPath: Path = frontier[x]
                
                if  (bestPath.total == nil) || (itemPath.total < bestPath.total) {
                    bestPath = itemPath
                    pathIndex = x
                }
                
            }
            
            
            
            //enumerate the bestPath edges
            for e in bestPath.destination.neighbors {
                
                let newPath: Path = Path()
                
                newPath.destination = e.neighbor
                newPath.previous = bestPath
                newPath.total = bestPath.total + e.weight
                
                
                //add the new path to the frontier
                frontier.append(newPath)
                
            }
            
            
            //preserve the bestPath
            finalPaths.append(bestPath)
            
            
            //remove the bestPath from the frontier
            //frontier.removeAtIndex(pathIndex) - Swift2
            frontier.remove(at: pathIndex)
            
            
            
        } //end while
        
        
    
        //establish the shortest path as an optional
        var shortestPath: Path! = Path()
        
        
        for itemPath in finalPaths {
            
            if (itemPath.destination.key == destination.key) {
                
                if  (shortestPath.total == nil) || (itemPath.total < shortestPath.total) {
                    shortestPath = itemPath
                }
                
            }
            
        }
        
        
        return shortestPath
        
    }
    
    
    
    ///an optimized version of Dijkstra's shortest path algorthim
    func processDijkstraWithHeap(_ source: Vertex, destination: Vertex) -> Path! {
        
        
        let frontier: PathHeap = PathHeap()
        let finalPaths: PathHeap = PathHeap()
        
        
        //use source edges to create the frontier
        for e in source.neighbors {
            
            let newPath: Path = Path()
            
            
            newPath.destination = e.neighbor
            newPath.previous = nil
            newPath.total = e.weight
            
            
            //add the new path to the frontier
            frontier.enQueue(newPath)
            
        }
        
        
        //construct the best path
        var bestPath: Path = Path()
        
        
        while frontier.count != 0 {
                        
            //use the greedy approach to obtain the best path
            bestPath = Path()
            bestPath = frontier.peek()
            
            
            //enumerate the bestPath edges
            for e in bestPath.destination.neighbors {
                
                let newPath: Path = Path()
                
                newPath.destination = e.neighbor
                newPath.previous = bestPath
                newPath.total = bestPath.total + e.weight
                
                
                //add the new path to the frontier
                frontier.enQueue(newPath)
                
            }
            
            
            //preserve the bestPaths that match destination
            if (bestPath.destination.key == destination.key) {
                finalPaths.enQueue(bestPath)
            }
            
            
            //remove the bestPath from the frontier
            frontier.deQueue()
            
            
        } //end while
        
        
        
        //obtain the shortest path from the heap
        var shortestPath: Path! = Path()
        shortestPath = finalPaths.peek()
        
        
        return shortestPath
        
    }
    
    
    //MARK: traversal algorithms
    
    
    //bfs traversal with inout closure function
    func traverse(_ startingv: Vertex, formula: (_ node: inout Vertex) -> ()) {

        
        //establish a new queue
        let graphQueue: Queue<Vertex> = Queue<Vertex>()
        
        
        //queue a starting vertex
        graphQueue.enQueue(startingv)
        
        
        while !graphQueue.isEmpty() {
            
            //traverse the next queued vertex
            var vitem: Vertex = graphQueue.deQueue() as Vertex!
            
            
            //add unvisited vertices to the queue
            for e in vitem.neighbors {
                if e.neighbor.visited == false {
                    print("adding vertex: \(e.neighbor.key!) to queue..")
                    graphQueue.enQueue(e.neighbor)
                }
            }
            

            /*
            notes: this demonstrates how to invoke a closure with an inout parameter.
            By passing by reference no return value is required.
            */
            
            //invoke formula
            formula(&vitem)
            
            
        } //end while
        
        
        print("graph traversal complete..")
        
        
    }

    
    
    
    //breadth first search
    func traverse(_ startingv: Vertex) {
        
        
        //establish a new queue
        let graphQueue: Queue<Vertex> = Queue<Vertex>()
        
        
        //queue a starting vertex
        graphQueue.enQueue(startingv)
        
        
        while !graphQueue.isEmpty() {
            
            //traverse the next queued vertex
            let vitem = graphQueue.deQueue() as Vertex!
            
            guard vitem != nil else {
                return
            }
            
            //add unvisited vertices to the queue
            for e in vitem!.neighbors {
                if e.neighbor.visited == false {
                    print("adding vertex: \(e.neighbor.key!) to queue..")
                    graphQueue.enQueue(e.neighbor)
                }
            }
            
            
            vitem!.visited = true
            print("traversed vertex: \(vitem!.key!)..")
            
            
        } //end while
        
        
        print("graph traversal complete..")
        
        
    } //end function
    
    
    
    //use bfs with trailing closure to update all values
    func update(startingv: Vertex, formula:((Vertex) -> Bool)) {
        
        
        //establish a new queue
        let graphQueue: Queue<Vertex> = Queue<Vertex>()
        
        
        //queue a starting vertex
        graphQueue.enQueue(startingv)
        
        
        while !graphQueue.isEmpty() {
            
            //traverse the next queued vertex
            let vitem = graphQueue.deQueue() as Vertex!            
            
            guard vitem != nil else {
                return
            }
            
            //add unvisited vertices to the queue
            for e in vitem!.neighbors {
                if e.neighbor.visited == false {
                    print("adding vertex: \(e.neighbor.key!) to queue..")
                    graphQueue.enQueue(e.neighbor)
                }
            }
            
            
            //apply formula..
            if formula(vitem!) == false {
                print("formula unable to update: \(vitem!.key)")
            }
            else {
                print("traversed vertex: \(vitem!.key!)..")
            }
            
            vitem!.visited = true
            
            
        } //end while
        
        
        print("graph traversal complete..")
        
        
    }

    

    
    
}

トライ

コンピュータサイエンスでは、デジタルツリーとも呼ばれ、時には基数ツリーやプレフィックスツリー(接頭辞で検索できるように)と呼ばれるトライは、一種の検索ツリーです。これは、動的な集合や連想を格納するために使用される順序付けられたツリーデータ構造ですキーは通常文字列です。 (ウィキペディア、 ソース

//
//  Trie.swift
//  SwiftStructures
//
//  Created by Wayne Bishop on 10/14/14.
//  Copyright (c) 2014 Arbutus Software Inc. All rights reserved.
//
import Foundation


public class Trie {
    
    private var root: TrieNode!
    
    
    init(){
        root = TrieNode()
    }
    
    
    
    //builds a tree hierarchy of dictionary content
    func append(word keyword: String) {
        
        
        //trivial case
        guard keyword.length > 0 else {
            return
        }
        
        
        var current: TrieNode = root
        
        
        while keyword.length != current.level {
            
            var childToUse: TrieNode!
            let searchKey = keyword.substring(to: current.level + 1)
            
            
            //print("current has \(current.children.count) children..")
            
            
            //iterate through child nodes
            for child in current.children {
                
                if (child.key == searchKey) {
                    childToUse = child
                    break
                }
                
            }
            
            
            //new node
            if childToUse == nil {
                
                childToUse = TrieNode()
                childToUse.key = searchKey
                childToUse.level = current.level + 1
                current.children.append(childToUse)
            }
            
            
            current = childToUse
            
            
        } //end while
        
        
        //final end of word check
        if (keyword.length == current.level) {
            current.isFinal = true
            print("end of word reached!")
            return
        }
        
        
        
    } //end function
    
    

    
    //find words based on the prefix
    func search(forWord keyword: String) -> Array<String>! {
        
        
        //trivial case
        guard keyword.length > 0 else {
            return nil
        }
        
        
        var current: TrieNode = root
        var wordList = Array<String>()
        
        
        while keyword.length != current.level {
            
            var childToUse: TrieNode!
            let searchKey = keyword.substring(to: current.level + 1)
            

            //print("looking for prefix: \(searchKey)..")
            
            
            //iterate through any child nodes
            for child in current.children {
                
                if (child.key == searchKey) {
                    childToUse = child
                    current = childToUse
                    break
                }
                
            }
            
 
            if childToUse == nil {
               return nil
            }
            
            
        } //end while
        
        
        
        //retrieve the keyword and any descendants
        if ((current.key == keyword) && (current.isFinal)) {
            wordList.append(current.key)
        }

        
        //include only children that are words
        for child in current.children {
            
            if (child.isFinal == true) {
                wordList.append(child.key)
            }
            
        }
        
        
        return wordList

        
    } //end function
    

}

(GitHub、 ソース

スタック

コンピュータサイエンスでは、スタックは、要素をコレクションに追加するpushと、まだ削除されていない最も最近追加された要素を削除するpopの2つの主要な操作を持つ、要素のコレクションとして機能する抽象データ型です。要素がスタックから外れる順序は、代替名LIFO(後入れ先出し)を発生させます。さらに、ピーク動作は、スタックを変更することなくトップにアクセスすることができる。 (ウィキペディア、 ソース

下記のライセンス情報とオリジナルコードソース( github )を参照してください。

//
//  Stack.swift
//  SwiftStructures
//
//  Created by Wayne Bishop on 8/1/14.
//  Copyright (c) 2014 Arbutus Software Inc. All rights reserved.
//
import Foundation


class Stack<T> {
    
    private var top: Node<T>
    
    init() {
        top = Node<T>()
    }
    
    
    //the number of items - O(n)
    var count: Int {
        
        
        //return trivial case
        guard top.key != nil else {
          return 0
        }
                
        
        var current = top
        var x: Int = 1
        
        
        //cycle through list
        while current.next != nil {
            current = current.next!
            x += 1
        }
            
        return x        
        
    }
    
    
    //add item to the stack
    func push(withKey key: T) {
        
        
        //return trivial case
        guard top.key != nil else {
            top.key = key
            return
        }
        
        
        //create new item
        let childToUse = Node<T>()
        childToUse.key = key
            
            
        //set new created item at top
        childToUse.next = top
        top = childToUse        

    }
    

    //remove item from the stack
    func pop() {
        
        if self.count > 1 {
            top = top.next
        }
        else {
            top.key = nil
        }
        
    }
    
    
    //retrieve the top most item
    func peek() -> T! {

        
        //determine instance
        if let topitem = top.key {
            return topitem
        }
            
        else {
            return nil
        }
        
    }
    
    
    
    //check for value
    func isEmpty() -> Bool {
        
        if self.count == 0 {
            return true
        }
        
        else {
            return false
        }
        
    }
    

}

MITライセンス(MIT)

Copyright(c)2015、Wayne Bishop&Arbutus Software Inc.

本ソフトウェアおよび関連するドキュメンテーションファイル(以下「本ソフトウェア」といいます)のコピーを取得した者は、本ソフトウェアを制限なく使用、複製、改変、マージする権利を含むがこれに限定されるものではなく、本ソフトウェアのコピーを発行、配布、サブライセンス許諾、および/または販売すること、および本ソフトウェアが提供されている人に、以下の条件に従うことを許可すること。

上記の著作権表示およびこの許可通知は、本ソフトウェアのすべてのコピーまたは実質的な部分に含まれるものとします。

本ソフトウェアは、商品性、特定の目的への適合性および非侵害性の保証を含むが、明示的または黙示的ないかなる保証もなく、現状のまま提供されます。作者または著作権者は、いかなる場合も、本ソフトウェアまたはその使用に関連して発生したものであっても、その使用に起因するものであっても、契約違反、その他の損害賠償その他の損害賠償の責任は負わないものとします。ソフトウェア。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow