mirror of
https://github.com/chai2010/advanced-go-programming-book.git
synced 2025-05-24 04:22:22 +00:00
ch2-6: 完善 qsort 例子
This commit is contained in:
parent
59a60a896c
commit
ffa45e65ca
@ -13,7 +13,7 @@ void qsort(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
其中base参数是要排序数组的首个元素的地址,num是数组中元素的个数,size是数组中每个元素的大小。最关键是cmp比较函数,用于对数组中任意两个元素进行排序。cmp排序函数的两个指针参数分别是要比较的两个元素的地址,如果第一个参数对应元素大于第二个参数对应的元素将返回1,如果两个元素相等则返回0,如果第一个元素小于第二个元素则返回-1。
|
其中base参数是要排序数组的首个元素的地址,num是数组中元素的个数,size是数组中每个元素的大小。最关键是cmp比较函数,用于对数组中任意两个元素进行排序。cmp排序函数的两个指针参数分别是要比较的两个元素的地址,如果第一个参数对应元素大于第二个参数对应的元素将返回结果大于0,如果两个元素相等则返回0,如果第一个元素小于第二个元素则返回结果小于0。
|
||||||
|
|
||||||
下面的例子是用C语言的qsort对一个int类型的数组进行排序:
|
下面的例子是用C语言的qsort对一个int类型的数组进行排序:
|
||||||
|
|
||||||
@ -48,14 +48,14 @@ int main() {
|
|||||||
/*
|
/*
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define DIM(x) (sizeof(x)/sizeof((x)[0]))
|
|
||||||
|
|
||||||
static int compare(const void* a, const void* b) {
|
static int compare(const void* a, const void* b) {
|
||||||
return ( *(int*)a - *(int*)b );
|
const int* pa = (int*)a;
|
||||||
|
const int* pb = (int*)b;
|
||||||
|
return *pa - *pb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qsort_proxy(int values[], size_t len, size_t elemsize) {
|
static void qsort_proxy(int* values, size_t len, size_t elemsize) {
|
||||||
qsort(values, DIM(values), sizeof(values[0]), compare);
|
qsort(values, len, sizeof(values[0]), compare);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
@ -64,16 +64,18 @@ import "unsafe"
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
values := []int32{ 42, 9, 101, 95, 27, 25 };
|
values := []int32{ 42, 9, 101, 95, 27, 25 };
|
||||||
C.qsort_proxy(
|
C.qsort_proxy(
|
||||||
unsafe.Pointer(&values[0]),
|
(*C.int)(unsafe.Pointer(&values[0])),
|
||||||
C.size_t(len(values)),
|
C.size_t(len(values)),
|
||||||
C.size_t(unsafe.Sizeof(values[0])),
|
C.size_t(unsafe.Sizeof(values[0])),
|
||||||
)
|
)
|
||||||
fmt.Println(values)
|
fmt.Println(values)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
因为 compare 函数固定了元素的大小,导致只能针对特点的数值类型排序。
|
||||||
|
|
||||||
## 在Go中自传入比较函数
|
## 在Go中自传入比较函数
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@ -81,16 +83,16 @@ func main() {
|
|||||||
extern int go_qsort_compare(void* a, void* b);
|
extern int go_qsort_compare(void* a, void* b);
|
||||||
|
|
||||||
static int compare(const void* a, const void* b) {
|
static int compare(const void* a, const void* b) {
|
||||||
return go_qsort_compare((void*)(a), (void*)(b))
|
return go_qsort_compare((void*)(a), (void*)(b));
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
//export go_qsort_compare
|
//export go_qsort_compare
|
||||||
func go_qsort_compare(a, b unsafe.Pointer) C.int {
|
func go_qsort_compare(a, b unsafe.Pointer) C.int {
|
||||||
pa := (*C.int)(a)
|
pa := (*C.int)(a)
|
||||||
pb := (*C.int)(b)
|
pb := (*C.int)(b)
|
||||||
return C.int(*pa - *pb)
|
return C.int(*pa - *pb)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -113,6 +115,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
直接传入Go导出的比较函数,需要进行一次类型转换(因为参数少了const修饰)。
|
||||||
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "C"
|
import "C"
|
||||||
|
9
examples/ch2-06-qsort/v1-qsort/Makefile
Normal file
9
examples/ch2-06-qsort/v1-qsort/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
# License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
default:
|
||||||
|
gcc main.c && ./a.out && rm a.out
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm a.out
|
27
examples/ch2-06-qsort/v1-qsort/main.c
Normal file
27
examples/ch2-06-qsort/v1-qsort/main.c
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define DIM(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
|
||||||
|
static int cmp(const void* a, const void* b) {
|
||||||
|
const int* pa = (int*)a;
|
||||||
|
const int* pb = (int*)b;
|
||||||
|
return *pa - *pb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int values[] = { 42, 8, 109, 97, 23, 25 };
|
||||||
|
int i;
|
||||||
|
|
||||||
|
qsort(values, DIM(values), sizeof(values[0]), cmp);
|
||||||
|
|
||||||
|
for(i = 0; i < DIM(values); i++) {
|
||||||
|
printf ("%d ",values[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
34
examples/ch2-06-qsort/v2-qsort/main.go
Normal file
34
examples/ch2-06-qsort/v2-qsort/main.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static int compare(const void* a, const void* b) {
|
||||||
|
const int* pa = (int*)a;
|
||||||
|
const int* pb = (int*)b;
|
||||||
|
return *pa - *pb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qsort_proxy(int* values, size_t len, size_t elemsize) {
|
||||||
|
qsort(values, len, sizeof(values[0]), compare);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
values := []int32{42, 9, 101, 95, 27, 25}
|
||||||
|
|
||||||
|
C.qsort_proxy(
|
||||||
|
(*C.int)(unsafe.Pointer(&values[0])),
|
||||||
|
C.size_t(len(values)),
|
||||||
|
C.size_t(unsafe.Sizeof(values[0])),
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println(values)
|
||||||
|
}
|
43
examples/ch2-06-qsort/v3-qsort/main.go
Normal file
43
examples/ch2-06-qsort/v3-qsort/main.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef int (*qsort_cmp_func_t)(const void* a, const void* b);
|
||||||
|
|
||||||
|
extern int go_qsort_compare(void* a, void* b);
|
||||||
|
|
||||||
|
static int compare(const void* a, const void* b) {
|
||||||
|
return go_qsort_compare((void*)(a), (void*)(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
static qsort_cmp_func_t get_compare_ptr() {
|
||||||
|
return compare;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
values := []int32{42, 9, 101, 95, 27, 25}
|
||||||
|
|
||||||
|
C.qsort(unsafe.Pointer(&values[0]),
|
||||||
|
C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])),
|
||||||
|
C.get_compare_ptr(),
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export go_qsort_compare
|
||||||
|
func go_qsort_compare(a, b unsafe.Pointer) C.int {
|
||||||
|
pa := (*C.int)(a)
|
||||||
|
pb := (*C.int)(b)
|
||||||
|
return C.int(*pa - *pb)
|
||||||
|
}
|
35
examples/ch2-06-qsort/v4-qsort/main.go
Normal file
35
examples/ch2-06-qsort/v4-qsort/main.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef int (*qsort_cmp_func_t)(const void* a, const void* b);
|
||||||
|
extern int go_qsort_compare(void* a, void* b);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
values := []int32{42, 9, 101, 95, 27, 25}
|
||||||
|
|
||||||
|
C.qsort(unsafe.Pointer(&values[0]),
|
||||||
|
C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])),
|
||||||
|
(C.qsort_cmp_func_t)(unsafe.Pointer(C.go_qsort_compare)),
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export go_qsort_compare
|
||||||
|
func go_qsort_compare(a, b unsafe.Pointer) C.int {
|
||||||
|
pa := (*C.int)(a)
|
||||||
|
pb := (*C.int)(b)
|
||||||
|
|
||||||
|
return C.int(*pa - *pb)
|
||||||
|
}
|
50
examples/ch2-06-qsort/v5-qsort/main.go
Normal file
50
examples/ch2-06-qsort/v5-qsort/main.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef int (*qsort_cmp_func_t)(const void* a, const void* b);
|
||||||
|
extern int go_qsort_compare(void* a, void* b);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
values := []int32{42, 9, 101, 95, 27, 25}
|
||||||
|
|
||||||
|
go_qsort_compare_info.Lock()
|
||||||
|
defer go_qsort_compare_info.Unlock()
|
||||||
|
|
||||||
|
go_qsort_compare_info.fn = func(a, b unsafe.Pointer) C.int {
|
||||||
|
pa := (*C.int)(a)
|
||||||
|
pb := (*C.int)(b)
|
||||||
|
return C.int(*pa - *pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
C.qsort(unsafe.Pointer(&values[0]),
|
||||||
|
C.size_t(len(values)), C.size_t(unsafe.Sizeof(values[0])),
|
||||||
|
(C.qsort_cmp_func_t)(unsafe.Pointer(C.go_qsort_compare)),
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export go_qsort_compare
|
||||||
|
func go_qsort_compare(a, b unsafe.Pointer) C.int {
|
||||||
|
return go_qsort_compare_info.fn(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var go_qsort_compare_info struct {
|
||||||
|
fn func(a, b unsafe.Pointer) C.int
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
56
examples/ch2-06-qsort/v6-qsort/main.go
Normal file
56
examples/ch2-06-qsort/v6-qsort/main.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef int (*qsort_cmp_func_t)(const void* a, const void* b);
|
||||||
|
extern int go_qsort_compare(void* a, void* b);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
values := []int32{42, 9, 101, 95, 27, 25}
|
||||||
|
|
||||||
|
qsort(values, func(a, b unsafe.Pointer) C.int {
|
||||||
|
pa := (*C.int)(a)
|
||||||
|
pb := (*C.int)(b)
|
||||||
|
return C.int(*pa - *pb)
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func qsort(values []int32, fn func(a, b unsafe.Pointer) C.int) {
|
||||||
|
go_qsort_compare_info.Lock()
|
||||||
|
defer go_qsort_compare_info.Unlock()
|
||||||
|
|
||||||
|
go_qsort_compare_info.fn = fn
|
||||||
|
|
||||||
|
C.qsort(
|
||||||
|
unsafe.Pointer(&values[0]),
|
||||||
|
C.size_t(len(values)),
|
||||||
|
C.size_t(unsafe.Sizeof(values[0])),
|
||||||
|
(C.qsort_cmp_func_t)(unsafe.Pointer(C.go_qsort_compare)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export go_qsort_compare
|
||||||
|
func go_qsort_compare(a, b unsafe.Pointer) C.int {
|
||||||
|
return go_qsort_compare_info.fn(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var go_qsort_compare_info struct {
|
||||||
|
fn func(a, b unsafe.Pointer) C.int
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
92
examples/ch2-06-qsort/v7-qsort/main.go
Normal file
92
examples/ch2-06-qsort/v7-qsort/main.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright © 2018 ChaiShushan <chaishushan{AT}gmail.com>.
|
||||||
|
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef int (*qsort_cmp_func_t)(const void* a, const void* b);
|
||||||
|
|
||||||
|
extern int go_qsort_compare(void* a, void* b);
|
||||||
|
extern void go_qsort_compare_save_base(void* base);
|
||||||
|
|
||||||
|
static void
|
||||||
|
qsort_proxy(
|
||||||
|
void* base, size_t num, size_t size,
|
||||||
|
int (*compare)(const void* a, const void* b)
|
||||||
|
) {
|
||||||
|
go_qsort_compare_save_base(base);
|
||||||
|
qsort(base, num, size, compare);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
values := []int64{42, 9, 101, 95, 27, 25}
|
||||||
|
|
||||||
|
fmt.Println(values)
|
||||||
|
defer fmt.Println(values)
|
||||||
|
|
||||||
|
qsort(values, func(i, j int) int {
|
||||||
|
return int(values[i] - values[j])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func qsort(slice interface{}, fn func(a, b int) int) {
|
||||||
|
sv := reflect.ValueOf(slice)
|
||||||
|
if sv.Kind() != reflect.Slice {
|
||||||
|
panic(fmt.Sprintf("qsort called with non-slice value of type %T", slice))
|
||||||
|
}
|
||||||
|
if sv.Len() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go_qsort_compare_info.Lock()
|
||||||
|
defer go_qsort_compare_info.Unlock()
|
||||||
|
|
||||||
|
// baseMem = unsafe.Pointer(sv.Index(0).Addr().Pointer())
|
||||||
|
// baseMem maybe moved, so must saved after call C.fn
|
||||||
|
go_qsort_compare_info.elemsize = sv.Type().Elem().Size()
|
||||||
|
go_qsort_compare_info.fn = fn
|
||||||
|
|
||||||
|
C.qsort_proxy(
|
||||||
|
unsafe.Pointer(unsafe.Pointer(sv.Index(0).Addr().Pointer())),
|
||||||
|
C.size_t(sv.Len()),
|
||||||
|
C.size_t(sv.Type().Elem().Size()),
|
||||||
|
(C.qsort_cmp_func_t)(unsafe.Pointer(C.go_qsort_compare)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export go_qsort_compare
|
||||||
|
func go_qsort_compare(a, b unsafe.Pointer) C.int {
|
||||||
|
var (
|
||||||
|
// array memory is locked
|
||||||
|
base = go_qsort_compare_info.base
|
||||||
|
elemsize = go_qsort_compare_info.elemsize
|
||||||
|
)
|
||||||
|
|
||||||
|
i := int((uintptr(a) - base) / elemsize)
|
||||||
|
j := int((uintptr(b) - base) / elemsize)
|
||||||
|
|
||||||
|
return C.int(go_qsort_compare_info.fn(i, j))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export go_qsort_compare_save_base
|
||||||
|
func go_qsort_compare_save_base(base unsafe.Pointer) {
|
||||||
|
go_qsort_compare_info.base = uintptr(base)
|
||||||
|
}
|
||||||
|
|
||||||
|
var go_qsort_compare_info struct {
|
||||||
|
base uintptr
|
||||||
|
elemsize uintptr
|
||||||
|
fn func(a, b int) int
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user