Go语言实现HashSet
set.go
// set project set.go
package set type Set interface {
Add(e interface{}) bool
Remove(e interface{})
Clear()
Contains(e interface{}) bool
Len() int
Same(other Set) bool
Elements() []interface{}
String() string
} // 将集合other添加到集合one中
func AddSet(one Set, other Set) {
if one == nil || other == nil || other.Len() == {
return
}
for _, v := range other.Elements() {
one.Add(v)
}
} // 判断集合 one 是否是集合 other 的超集
func IsSuperset(one Set, other Set) bool {
if one == nil || other == nil {
return false
}
oneLen := one.Len()
otherLen := other.Len()
if oneLen == || oneLen <= otherLen {
return false
}
if oneLen > && otherLen == {
return true
}
for _, v := range other.Elements() {
if !one.Contains(v) {
return false
}
}
return true
} // 生成集合 one 和集合 other 的并集
func Union(one Set, other Set) Set {
if one == nil && other == nil {
return nil
}
unionedSet := NewSimpleSet()
AddSet(unionedSet, one)
AddSet(unionedSet, other)
return unionedSet
} // 生成集合 one 和集合 other 的交集
func Intersect(one Set, other Set) Set {
if one == nil || other == nil {
return nil
}
intersectedSet := NewSimpleSet()
if one.Len() == || other.Len() == {
return intersectedSet
}
if one.Len() < other.Len() {
for _, v := range one.Elements() {
if other.Contains(v) {
intersectedSet.Add(v)
}
}
} else {
for _, v := range other.Elements() {
if one.Contains(v) {
intersectedSet.Add(v)
}
}
}
return intersectedSet
} // 生成集合 one 对集合 other 的差集
func Difference(one Set, other Set) Set {
if one == nil {
return nil
}
differencedSet := NewSimpleSet()
if other == nil || other.Len() == {
AddSet(differencedSet, one)
return differencedSet
}
for _, v := range one.Elements() {
if !other.Contains(v) {
differencedSet.Add(v)
}
}
return differencedSet
} // 生成集合 one 和集合 other 的对称差集
func SymmetricDifference(one Set, other Set) Set {
diffA := Difference(one, other)
if other == nil || other.Len() == {
return diffA
}
diffB := Difference(other, one)
return Union(diffA, diffB)
} // 返回一个HashSet
func NewSimpleSet() Set {
return NewHashSet()
} // 判断给定value是否为集合
func IsSet(value interface{}) bool {
if _, ok := value.(Set); ok {
return true
}
return false
}
hash_set.go
// hash_set
package set import (
"bytes"
"fmt"
) type HashSet struct {
m map[interface{}]bool
} // 创建和初始化HashSet的方法
func NewHashSet() *HashSet {
return &HashSet{m: make(map[interface{}]bool)}
} // 向HashSet中添加元素的方法
func (set *HashSet) Add(e interface{}) bool {
if !set.m[e] {
set.m[e] = true
return true
}
return false
} // 删除HashSet中指定的元素
func (set *HashSet) Remove(e interface{}) {
delete(set.m, e)
} // 清除HashSet中的所有元素
func (set *HashSet) Clear() {
set.m = make(map[interface{}]bool)
} // 判断HashSet是否包含指定元素
func (set *HashSet) Contains(e interface{}) bool {
return set.m[e]
} // 获取HashSet中元素值数量
func (set *HashSet) Len() int {
return len(set.m)
} // 判断两个Set类型值是否相同
func (set *HashSet) Same(other Set) bool {
if other == nil {
return false
}
if set.Len() != other.Len() {
return false
}
for key := range set.m {
if !other.Contains(key) {
return false
}
}
return true
} // 生成HashSet的一个快照
func (set *HashSet) Elements() []interface{} {
initialLen := len(set.m)
snapshot := make([]interface{}, initialLen)
actualLen :=
for key := range set.m {
if actualLen < initialLen {
snapshot[actualLen] = key
} else {
snapshot = append(snapshot, key)
}
actualLen++
}
if actualLen < initialLen {
snapshot = snapshot[:actualLen]
}
return snapshot
} // 获取HashSet自身字符串表示形式
func (set *HashSet) String() string {
var buf bytes.Buffer
buf.WriteString("Set{")
first := true
for key := range set.m {
if first {
first = false
} else {
buf.WriteString(" ")
}
buf.WriteString(fmt.Sprintf("%v", key))
}
buf.WriteString("}")
return buf.String()
}
功能测试:
set_test.go
// set_test
package set import (
"bytes"
"fmt"
"math/rand"
"runtime/debug"
"strings"
"testing"
"time"
) func testSetLenAndContains(t *testing.T, newSet func() Set, typeName string) {
t.Logf("Starting Test%sLenAndContains...", typeName)
set, expectedElemMap := genRandSet(newSet)
t.Logf("Got a %s value: %v.", typeName, set)
expectedLen := len(expectedElemMap)
if set.Len() != expectedLen {
t.Errorf("ERROR: The length of %s value %d is not %d!\n",
set.Len(), typeName, expectedLen)
t.FailNow()
}
t.Logf("The length of %s value is %d.\n", typeName, set.Len())
for k := range expectedElemMap {
if !set.Contains(k) {
t.Errorf("ERROR: The %s value %v do not contains %v!",
set, typeName, k)
t.FailNow()
}
}
} func testSetAdd(t *testing.T, newSet func() Set, typeName string) {
t.Logf("Starting Test%sAdd...", typeName)
set := newSet()
var randElem interface{}
var result bool
expectedElemMap := make(map[interface{}]bool)
for i := ; i < ; i++ {
randElem = genRandElement()
t.Logf("Add %v to the %s value %v.\n", randElem, typeName, set)
result = set.Add(randElem)
if expectedElemMap[randElem] && result {
t.Errorf("ERROR: The element adding (%v => %v) is successful but should be failing!\n",
randElem, set)
t.FailNow()
}
if !expectedElemMap[randElem] && !result {
t.Errorf("ERROR: The element adding (%v => %v) is failing!\n",
randElem, set)
t.FailNow()
}
expectedElemMap[randElem] = true
}
t.Logf("The %s value: %v.", typeName, set)
expectedLen := len(expectedElemMap)
if set.Len() != expectedLen {
t.Errorf("ERROR: The length of %s value %d is not %d!\n",
set.Len(), typeName, expectedLen)
t.FailNow()
}
t.Logf("The length of %s value is %d.\n", typeName, set.Len())
for k := range expectedElemMap {
if !set.Contains(k) {
t.Errorf("ERROR: The %s value %v do not contains %v!",
set, typeName, k)
t.FailNow()
}
}
} func testSetRemove(t *testing.T, newSet func() Set, typeName string) {
t.Logf("Starting Test%sRemove...", typeName)
set, expectedElemMap := genRandSet(newSet)
t.Logf("Got a %s value: %v.", typeName, set)
t.Logf("The length of %s value is %d.\n", typeName, set.Len())
var number int
for k, _ := range expectedElemMap {
if number% == {
t.Logf("Remove %v from the HashSet value %v.\n", k, set)
set.Remove(k)
if set.Contains(k) {
t.Errorf("ERROR: The element removing (%v => %v) is failing!\n",
k, set)
t.FailNow()
}
delete(expectedElemMap, k)
}
number++
}
expectedLen := len(expectedElemMap)
if set.Len() != expectedLen {
t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", set.Len(), expectedLen)
t.FailNow()
}
t.Logf("The length of %s value is %d.\n", typeName, set.Len())
for _, v := range set.Elements() {
if !expectedElemMap[v] {
t.Errorf("ERROR: The HashSet value %v contains %v but should not contains!", set, v)
t.FailNow()
}
}
} func testSetClear(t *testing.T, newSet func() Set, typeName string) {
t.Logf("Starting Test%sClear...", typeName)
set, _ := genRandSet(newSet)
t.Logf("Got a %s value: %v.", typeName, set)
t.Logf("The length of %s value is %d.\n", typeName, set.Len())
t.Logf("Clear the HashSet value %v.\n", set)
set.Clear()
expectedLen :=
if set.Len() != expectedLen {
t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", set.Len(), expectedLen)
t.FailNow()
}
t.Logf("The length of %s value is %d.\n", typeName, set.Len())
} func testSetElements(t *testing.T, newSet func() Set, typeName string) {
t.Logf("Starting Test%sElements...", typeName)
set, expectedElemMap := genRandSet(newSet)
t.Logf("Got a %s value: %v.", typeName, set)
t.Logf("The length of %s value is %d.\n", typeName, set.Len())
elems := set.Elements()
t.Logf("The elements of %s value is %v.\n", typeName, elems)
expectedLen := len(expectedElemMap)
if len(elems) != expectedLen {
t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", len(elems), expectedLen)
t.FailNow()
}
t.Logf("The length of elements is %d.\n", len(elems))
for _, v := range elems {
if !expectedElemMap[v] {
t.Errorf("ERROR: The elements %v contains %v but should not contains!", set, v)
t.FailNow()
}
}
} func testSetSame(t *testing.T, newSet func() Set, typeName string) {
t.Logf("Starting Test%sSame...", typeName)
set, _ := genRandSet(newSet)
t.Logf("Got a %s value: %v.", typeName, set)
t.Logf("The length of %s value is %d.\n", typeName, set.Len())
set2 := newSet()
t.Logf("Clone the HashSet value %v...\n", set)
for _, v := range set.Elements() {
set2.Add(v)
}
result := set2.Same(set)
if !result {
t.Errorf("ERROR: Two sets are not same!")
}
t.Logf("Two sets are same.")
} func testSetString(t *testing.T, newSet func() Set, typeName string) {
t.Logf("Starting Test%sString...", typeName)
set, _ := genRandSet(newSet)
t.Logf("Got a %s value: %v.", typeName, set)
setStr := set.String()
t.Logf("The string of %s value is %s.\n", typeName, setStr)
var elemStr string
for _, v := range set.Elements() {
elemStr = fmt.Sprintf("%v", v)
if !strings.Contains(setStr, elemStr) {
t.Errorf("ERROR: The string of %s value %s do not contains %s!",
typeName, setStr, elemStr)
t.FailNow()
}
}
} // ----- Set 公用函数测试 ----- func TestIsSuperset(t *testing.T) {
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
t.Errorf("Fatal Error: %s\n", err)
}
}()
t.Log("Starting TestIsSuperset...")
set, _ := genRandSet(func() Set { return NewSimpleSet() })
set2 := NewSimpleSet()
for _, v := range set.Elements() {
set2.Add(v)
}
for extraElem := genRandElement(); ; {
if set2.Add(extraElem) {
break
} else {
time.Sleep( * time.Millisecond)
}
}
if !IsSuperset(set2, set) {
t.Errorf("ERROR: The HashSet value %v is not a superset of %v!\n", set2, set)
t.FailNow()
} else {
t.Logf("The HashSet value %v is a superset of %v.\n", set2, set)
}
for extraElem := genRandElement(); ; {
if set.Add(extraElem) {
break
} else {
time.Sleep( * time.Millisecond)
}
}
if IsSuperset(set2, set) {
t.Errorf("ERROR: The HashSet value %v should not be a superset of %v!\n", set2, set)
t.FailNow()
} else {
t.Logf("The HashSet value %v is not a superset of %v.\n", set2, set)
}
} func TestUnion(t *testing.T) {
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
t.Errorf("Fatal Error: %s\n", err)
}
}()
t.Log("Starting TestUnion...")
set, _ := genRandSet(func() Set { return NewSimpleSet() })
t.Logf("The set value: %v", set)
set2, _ := genRandSet(func() Set { return NewSimpleSet() })
uSet := Union(set, set2)
t.Logf("The set value (2): %v", set2)
for _, v := range set.Elements() {
if !uSet.Contains(v) {
t.Errorf("ERROR: The union set value %v do not contains %v!",
uSet, v)
t.FailNow()
}
}
for _, v := range set2.Elements() {
if !uSet.Contains(v) {
t.Errorf("ERROR: The union set value %v do not contains %v!",
uSet, v)
t.FailNow()
}
}
t.Logf("The set value %v is a unioned set of %v and %v", uSet, set, set2)
} func TestIntersect(t *testing.T) {
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
t.Errorf("Fatal Error: %s\n", err)
}
}()
t.Log("Starting TestIntersect...")
commonElem := genRandElement()
set, _ := genRandSet(func() Set { return NewSimpleSet() })
set.Add(commonElem)
t.Logf("The set value: %v", set)
set2, _ := genRandSet(func() Set { return NewSimpleSet() })
set2.Add(commonElem)
t.Logf("The set value (2): %v", set2)
iSet := Intersect(set, set2)
for _, v := range iSet.Elements() {
if !set.Contains(v) {
t.Errorf("ERROR: The set value %v do not contains %v!",
set, v)
t.FailNow()
}
if !set2.Contains(v) {
t.Errorf("ERROR: The set value %v do not contains %v!",
set2, v)
t.FailNow()
}
}
t.Logf("The set value %v is a intersected set of %v and %v", iSet, set, set2)
} func TestDifference(t *testing.T) {
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
t.Errorf("Fatal Error: %s\n", err)
}
}()
t.Log("Starting TestDifference...")
commonElem := genRandElement()
set, _ := genRandSet(func() Set { return NewSimpleSet() })
set.Add(commonElem)
t.Logf("The set value: %v", set)
set2, _ := genRandSet(func() Set { return NewSimpleSet() })
set2.Add(commonElem)
t.Logf("The set value (2): %v", set2)
dSet := Difference(set, set2)
for _, v := range dSet.Elements() {
if !set.Contains(v) {
t.Errorf("ERROR: The set value %v do not contains %v!",
set, v)
t.FailNow()
}
if set2.Contains(v) {
t.Errorf("ERROR: The set value %v contains %v!",
set2, v)
t.FailNow()
}
}
t.Logf("The set value %v is a differenced set of %v to %v", dSet, set, set2)
} func TestSymmetricDifference(t *testing.T) {
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
t.Errorf("Fatal Error: %s\n", err)
}
}()
t.Log("Starting TestSymmetricDifference...")
commonElem := genRandElement()
set, _ := genRandSet(func() Set { return NewSimpleSet() })
set.Add(commonElem)
t.Logf("The set value: %v", set)
set2, _ := genRandSet(func() Set { return NewSimpleSet() })
set2.Add(commonElem)
t.Logf("The set value (2): %v", set2)
sdSet := SymmetricDifference(set, set2)
for _, v := range sdSet.Elements() {
if set.Contains(v) && set2.Contains(v) {
t.Errorf("ERROR: The element %v can not be a common element of %v to %v!",
v, set, set2)
t.FailNow()
}
}
t.Logf("The set value %v is a symmetric differenced set of %v to %v", sdSet, set, set2)
} // ----- 随机测试对象生成函数 ----- func genRandSet(newSet func() Set) (set Set, elemMap map[interface{}]bool) {
set = newSet()
elemMap = make(map[interface{}]bool)
var enough bool
for !enough {
e := genRandElement()
set.Add(e)
elemMap[e] = true
if len(elemMap) >= {
enough = true
}
}
return
} func genRandElement() interface{} {
seed := rand.Int63n()
switch seed {
case :
return genRandInt()
case :
return genRandString()
case :
return struct {
num int64
str string
}{genRandInt(), genRandString()}
default:
const length =
arr := new([length]interface{})
for i := ; i < length; i++ {
if i% == {
arr[i] = genRandInt()
} else {
arr[i] = genRandString()
}
}
return *arr
}
} func genRandString() string {
var buff bytes.Buffer
var prev string
var curr string
for i := ; buff.Len() < ; i++ {
curr = string(genRandAZAscii())
if curr == prev {
continue
} else {
prev = curr
}
buff.WriteString(curr)
}
return buff.String()
} func genRandAZAscii() int {
min := // A
max := // Z
rand.Seed(time.Now().UnixNano())
return min + rand.Intn(max-min)
} func genRandInt() int64 {
return rand.Int63n()
}
hash_set_test.go
// hash_set_test
package set import (
"fmt"
"runtime/debug"
"strings"
"testing"
) func TestHashSetCreation(t *testing.T) {
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
t.Errorf("Fatal Error: %s\n", err)
}
}()
t.Log("Starting TestHashSetCreation...")
hs := NewHashSet()
t.Logf("Create a HashSet value: %v\n", hs)
if hs == nil {
t.Errorf("The result of func NewHashSet is nil!\n")
}
isSet := IsSet(hs)
if !isSet {
t.Errorf("The value of HashSet is not Set!\n")
} else {
t.Logf("The HashSet value is a Set.\n")
}
} func TestHashSetLenAndContains(t *testing.T) {
testSetLenAndContains(t, func() Set { return NewHashSet() }, "HashSet")
} func TestHashSetAdd(t *testing.T) {
testSetAdd(t, func() Set { return NewHashSet() }, "HashSet")
} func TestHashSetRemove(t *testing.T) {
testSetRemove(t, func() Set { return NewHashSet() }, "HashSet")
} func TestHashSetClear(t *testing.T) {
testSetClear(t, func() Set { return NewHashSet() }, "HashSet")
} func TestHashSetElements(t *testing.T) {
testSetElements(t, func() Set { return NewHashSet() }, "HashSet")
} func TestHashSetSame(t *testing.T) {
testSetSame(t, func() Set { return NewHashSet() }, "HashSet")
} func TestSetString(t *testing.T) {
testSetString(t, func() Set { return NewHashSet() }, "HashSet")
} func testSetOp(t *testing.T) {
defer func() {
if err := recover(); err != nil {
debug.PrintStack()
t.Errorf("Fatal Error: %s\n", err)
}
}()
fmt.Println()
t.Logf("Starting TestHashSetOp...")
hs := NewHashSet()
if hs.Len() != {
t.Errorf("ERROR: The length of original HashSet value is not 0!\n")
t.FailNow()
}
randElem := genRandElement()
expectedElemMap := make(map[interface{}]bool)
t.Logf("Add %v to the HashSet value %v.\n", randElem, hs)
hs.Add(randElem)
expectedElemMap[randElem] = true
expectedLen := len(expectedElemMap)
if hs.Len() != expectedLen {
t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", hs.Len(), expectedLen)
t.FailNow()
}
var result bool
for i := ; i < ; i++ {
randElem = genRandElement()
t.Logf("Add %v to the HashSet value %v.\n", randElem, hs)
result = hs.Add(randElem)
if expectedElemMap[randElem] && result {
t.Errorf("ERROR: The element adding (%v => %v) is successful but should be failing!\n",
randElem, hs)
t.FailNow()
}
if !expectedElemMap[randElem] && !result {
t.Errorf("ERROR: The element adding (%v => %v) is failing!\n",
randElem, hs)
t.FailNow()
}
expectedElemMap[randElem] = true
}
expectedLen = len(expectedElemMap)
if hs.Len() != expectedLen {
t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", hs.Len(), expectedLen)
t.FailNow()
}
for k, _ := range expectedElemMap {
if !hs.Contains(k) {
t.Errorf("ERROR: The HashSet value %v do not contains %v!", hs, k)
t.FailNow()
}
}
number :=
for k, _ := range expectedElemMap {
if number% == {
t.Logf("Remove %v from the HashSet value %v.\n", k, hs)
hs.Remove(k)
if hs.Contains(k) {
t.Errorf("ERROR: The element adding (%v => %v) is failing!\n",
randElem, hs)
t.FailNow()
}
delete(expectedElemMap, k)
}
number++
}
expectedLen = len(expectedElemMap)
if hs.Len() != expectedLen {
t.Errorf("ERROR: The length of HashSet value %d is not %d!\n", hs.Len(), expectedLen)
t.FailNow()
}
for _, v := range hs.Elements() {
if !expectedElemMap[v] {
t.Errorf("ERROR: The HashSet value %v contains %v!", hs, v)
t.FailNow()
}
}
hs2 := NewHashSet()
for k, _ := range expectedElemMap {
hs2.Add(k)
}
if !hs.Same(hs2) {
t.Errorf("ERROR: HashSet value %v do not same %v!\n", hs, hs2)
t.FailNow()
}
str := hs.String()
t.Logf("The string of HashSet value %v is '%s'.\n", hs, str)
for _, v := range hs.Elements() {
if !strings.Contains(str, fmt.Sprintf("%v", v)) {
t.Errorf("ERROR: '%s' do not contains '%v'!", str, v)
t.FailNow()
}
}
}
Go语言实现HashSet的更多相关文章
- Go目录
1. Go语言获取项目当前路径 2. Go语言TCP/UDP Socket编程 3. Go语言实现HashSet
- Haskell语言学习笔记(77)Data.HashSet
安装 unordered-containers $ cabal install unordered-containers Installed unordered-containers-0.2.9.0 ...
- [Java语言] HashMap,HashSet,Hashtable,Vector,ArrayList 的关系 <转>
这么几个比较常用的但是比较容易混淆的概念同出于 java.util 包.本文仅作几个类的浅度解析. (本文基于JDK1.7,源码来自openjdk1.7.) ├── Collection │ ├── ...
- 学Android开发,入门语言java知识点
学Android开发,入门语言java知识点 Android是一种以Linux为基础的开源码操作系统,主要使用于便携设备,而linux是用c语言和少量汇编语言写成的,如果你想研究Android,就去学 ...
- Spring表达式语言 之 5.3 SpEL语法(拾肆)
5.3 SpEL语法 5.3.1 基本表达式 一.字面量表达式: SpEL支持的字面量包括:字符串.数字类型(int.long.float.double).布尔类型.null类型. 类型 示例 字 ...
- Apache Thrift - 可伸缩的跨语言服务开发框架
To put it simply, Apache Thrift is a binary communication protocol 原文地址:http://www.ibm.com/developer ...
- 微软在 .NET 3.5 新增了一个 HashSet 类,在 .NET 4 新增了一个 SortedSet 类,本文介绍他们的特性,并比较他们的异同。
微软在 .NET 3.5 新增了一个 HashSet 类,在 .NET 4 新增了一个 SortedSet 类,本文介绍他们的特性,并比较他们的异同. .NET Collection 函数库的 Has ...
- 【原创】关于hashcode和equals的不同实现对HashMap和HashSet集合类的影响的探究
这篇文章做了一个很好的测试:http://blog.csdn.net/afgasdg/article/details/6889383,判断往HashSet(不允许元素重复)里塞对象时,是如何判定set ...
- 笔记整理——C语言-http-1
http 传输原理及格式 - friping - ITeye技术网站 - Google Chrome (2013/4/1 14:02:36) http 传输原理及格式 博客分类: 其他 应用服务器浏览 ...
随机推荐
- ASP.NET 5系列教程 (六): 在 MVC6 中创建 Web API
ASP.NET 5.0 的主要目标之一是统一MVC 和 Web API 框架应用. 接下来几篇文章中您会了解以下内容: ASP.NET MVC 6 中创建简单的web API. 如何从空的项目模板中启 ...
- 记录js的一些小技巧
1.取数组最大值,最小值 Math.max.apply(null,[1,2,3,32,3]); Math.min.apply(null,[1,2,3,32,3]); 2.旧版IE setTimeout ...
- paip.java 调用c++ dll so总结
paip.java 调用c++ dll so总结 ///////JNA (这个ms sun 的) 我目前正做着一个相关的项目,说白了JNA就是JNI的替代品,以前用JNI需要编译一层中间库,现在JNA ...
- 从MySQL 5.5到5.7看复制的演进
概要:MySQL 5.5 支持单线程模式复制,MySQL 5.6 支持库级别的并行复制,MySQL 5.7 支持事务级别并行复制.结合这个主线我们可以来分析一下MySQL以及社区发展的一个前因后果. ...
- Java band [Cite]
SampleModel 取样模型Databuffer 数据缓冲区 Raster 光栅Sample 样本band 带 SampleModel是java awt中的一个抽象类,它定义了一个接口,用于提 ...
- 多功能表单填报系统V1.2.1-适用于在线报名系统、调查、数据收集等
多功能表单系统V1.2.1 前台:http://www.schoolms.net/mysoft/biaodan/index.asp 后台:http://www.schoolms.net/myso ...
- 漫谈Puppet4
激动人心的改进 速度,速度,还是速度 稳定性和鲁棒性的提升 全新的Parser “不变"的agent 不兼容的改动 包管理方式的变化 配置文件/目录的路径变化 其他路径变化 Director ...
- Linear or non-linear shadow maps?
Quote: Original post by RobMaddisonI understand that, for aliasing mitigation, it might be beneficia ...
- Ubuntu下无法安装sun-java6-jdk的解决办法
http://blog.sina.com.cn/s/blog_6296abc601018p86.html 这个帖子是讲怎么添加一个新的源, deb http://us.archive.ubuntu.c ...
- 2015想做O2O?那就来看看O2O报告!
来源:互联网