Ring a Bell : Three Sort Algorithms

本文详细介绍了排序算法中的梅尔排序与希尔排序的基本原理、实现方式及工作流程。梅尔排序通过将列表分为两半并递归排序来实现高效排序;而希尔排序则通过创建多个子列表并使用插入排序进行初步排序,最终通过逐步减小子列表间隔完成整个列表的排序。
 

The detail contents of how to code and how it works just lie in the book written by Simon Harris and James Ross, want to know more? so check it out.

A general implementation of mergesort is, when there is more than one item in the list to be sorted, split the list in half, sort the halves, and then merge them together.

Shellsort breaks a large list of items into many smaller sublists, which are sorted independently using an insertion sort. While this sounds simple, the trick lies in repeating this process several times with careful creation of larger and larger sublists, until the whole list is sorted using an insertion sort on the final pass. The shellsort code works by successively sorting sublists of items that are evenly spaced inside the larger list of items. These lists start out with few items in them, with large gaps between the items. The sublists become progressively larger in size but fewer in number as the items are more closely spaced. The outermost loop in the main sort() method is concerned with H-sorting the sublists at progressively smaller increments, eventually H-sorting with H set to a value of 1, which means the list is completely sorted.

The first step in quicksort is to choose the partitioning item. This is the item that ends up in its final sorted position after this pass, and partitions the list into sections, with smaller items to the left and larger items to its right. You also initialize two indexes at the leftmost and rightmost of the remaining items. The algorithm proceeds by advancing the left and right indexes towards each other until they meet. As the left index proceeds, it stops when it finds an item that is larger than the partitioning item. As the right index proceeds, it stops when it encounters an item that is smaller than the partitioning item. The items are then swapped so that they are each in the appropriate part of the list. Remember that the idea is to have smaller items to the left and larger items to the right, althought not necessarily in sorted order.

<think> 我们遇到了错误提示:`ee.Algorithms.Not is not a function`。在Google Earth Engine中,`ee.Algorithms.Not`确实不存在。我们需要使用其他方式来实现逻辑非操作。 在GEE中,逻辑操作通常通过以下方式实现: - 逻辑非:使用`ee.Number(1).subtract(condition)` 或者 `condition.not()`(如果condition是布尔类型) - 逻辑与:`condition1.and(condition2)` - 逻辑或:`condition1.or(condition2)` 另外,我们也可以使用`ee.Algorithms.If`来根据条件返回不同的值,但注意`ee.Algorithms`模块并没有提供直接的逻辑操作函数(如`Not`)。 因此,我们需要修改代码中的逻辑非操作。具体来说,错误出现在以下行: ```javascript var imageValid = ee.Algorithms.Not(ee.Algorithms.IsEqual(temperatureImage.get('is_valid'), 1)); ``` 我们可以改为: ```javascript var imageValid = ee.Algorithms.IsEqual(temperatureImage.get('is_valid'), 1).not(); ``` 但需要注意的是,`get('is_valid')`返回的是一个`ee.ComputedObject`,我们需要确保它被转换为布尔类型或者使用`ee.Number`进行比较。然而,`not()`方法只能用于`ee.Number`或`ee.Boolean`类型的对象。因此,我们也可以使用: ```javascript var imageValid = ee.Number(1).subtract(ee.Algorithms.IsEqual(temperatureImage.get('is_valid'), 1)); ``` 但这样得到的是数字(1-条件结果,条件结果为0或1),这可能不适合作为条件使用。因为条件表达式需要布尔类型(或0/1数字)?实际上,在`ee.Algorithms.If`中,条件需要是一个布尔类型的服务器端对象,但GEE中通常用0和1来表示,所以我们可以使用数字比较。 然而,更直接的方式是使用`not()`方法。但我们必须确保前面的比较返回的是布尔类型(实际上,`ee.Algorithms.IsEqual`返回的是一个整数0或1,而不是布尔类型?)。在GEE中,比较操作返回的是整数(0或1),因此我们不能直接使用`.not()`,因为整数没有`not`方法。 因此,我们可以这样处理: 1. 将比较结果转换为布尔类型,然后使用`not()`,或者 2. 使用`ee.Number`的`eq(0)`来实现逻辑非。 这里我们采用第二种方法,因为比较结果已经是0或1,我们可以用: ```javascript var imageValid = ee.Algorithms.IsEqual(temperatureImage.get('is_valid'), 1).eq(0); ``` 因为如果相等返回1,那么1.eq(0)就是0(false),如果不相等返回0,0.eq(0)就是1(true)。这正好是逻辑非。 但是,这样会变得复杂。我们也可以直接使用: ```javascript var imageValid = ee.Algorithms.NotEqual(temperatureImage.get('is_valid'), 1); ``` 但是,GEE中并没有`ee.Algorithms.NotEqual`。所以我们可以用: ```javascript var imageValid = ee.Algorithms.IsEqual(temperatureImage.get('is_valid'), 1).not(); ``` 但注意,`ee.Algorithms.IsEqual`返回的是整数,整数没有`not`方法。所以我们需要先把它转为布尔值?实际上,在GEE中,整数0和1可以直接用`ee.Number`的`not`方法(但是`not`方法只对0返回1,对非0返回0,这不符合我们的需求,因为我们想要的是:当相等时为0,不相等时为1,即逻辑非)。 实际上,我们想要的是:如果`is_valid`不等于1,则`imageValid`为真(1),否则为假(0)。所以: ```javascript var imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); ``` 这样,当`is_valid`为1时,`neq(1)`返回0,否则返回1。但注意,我们想要的是逻辑非,即原来的条件为真(1)时,我们想要假(0);条件为假(0)时,我们想要真(1)。所以这样并不对。 实际上,我们想要的是:原条件(相等)的否定。所以: 原条件:`is_valid == 1` -> 我们想要 `is_valid != 1` 因此,我们可以使用: ```javascript var imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); ``` 这样,当`is_valid`不等于1时,`imageValid`为1(真);等于1时,为0(假)。这符合我们的逻辑。 因此,我们可以将所有的`ee.Algorithms.Not(ee.Algorithms.IsEqual(...))`替换为`ee.Number(...).neq(1)`。 但是,请注意,`temperatureImage.get('is_valid')`可能是未定义的(如果图像没有这个属性)?在我们的代码中,我们设置了`is_valid`属性,所以应该没问题。 所以,修改后的代码中,我们将使用: ```javascript var imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); ``` 这样修改后,应该可以避免使用`ee.Algorithms.Not`。 现在,我们重写整个`getAnnualTemperature`函数中的相关部分。 注意:在GEE中,使用`ee.Number`来确保类型是数字,然后使用`neq`方法。 我们修改三处: 1. 第一次有效性检查(MODIS之后) 2. 第二次有效性检查(ERA5之后) 3. 最终有效性检查(GLDAS之后) 同时,我们也要修改最后返回时的条件判断,那里使用了`ee.Algorithms.If`,条件部分我们同样使用`ee.Number(...).neq(1)`。 但是,注意最后返回时的条件: ```javascript return ee.Algorithms.If({ condition: isValid, // 这里我们希望isValid为真(非0)时,返回有效图像;否则返回无效图像 ... }); ``` 而我们的`isValid`现在是一个ee.Number对象(0或1),可以直接作为条件,因为GEE的条件表达式接受数值(0为假,非0为真)?实际上,在`ee.Algorithms.If`中,条件应该是一个整数(0表示假,非0表示真)或者一个布尔类型(但GEE中布尔类型也是用0和1表示的)。所以这样是可以的。 因此,我们修改后的代码为: ```javascript // 3. 温度数据处理函数 - 修复服务器端比较问题 function getAnnualTemperature(year) { var startDate = ee.Date.fromYMD(year, 1, 1); var endDate = startDate.advance(1, 'year'); // 定义无效图像标记 var invalidImage = ee.Image().set('is_valid', 0); // 尝试不同数据源 var modisDay = datasets.modis_day .filterDate(startDate, endDate) .filterBounds(regionGeometry); // 检查MODIS白天数据是否可用 var modisDayAvailable = modisDay.size().gt(0); // 处理MODIS数据 var temperatureImage = ee.Image( ee.Algorithms.If({ condition: modisDayAvailable, trueCase: modisDay.mean() .multiply(0.02).subtract(273.15) .rename('temp_day'), falseCase: invalidImage }) ); // 正确检查图像有效性 (服务器端方法): 如果 is_valid 不等于1,说明无效,需要尝试下一个数据源 var imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); // 如果MODIS不可用,尝试ERA5 temperatureImage = ee.Image( ee.Algorithms.If({ condition: imageValid, trueCase: ee.Algorithms.If({ condition: datasets.era5 .filterDate(startDate, endDate) .filterBounds(regionGeometry) .size().gt(0), trueCase: datasets.era5 .filterDate(startDate, endDate) .filterBounds(regionGeometry) .mean() .subtract(273.15) .rename('era5_temp'), falseCase: invalidImage }), falseCase: temperatureImage }) ); // 更新有效性检查 (服务器端方法) imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); // 如果ERA5不可用,尝试GLDAS temperatureImage = ee.Image( ee.Algorithms.If({ condition: imageValid, trueCase: ee.Algorithms.If({ condition: datasets.gldas .filterDate(startDate, endDate) .filterBounds(regionGeometry) .size().gt(0), trueCase: datasets.gldas .filterDate(startDate, endDate) .filterBounds(regionGeometry) .mean() .subtract(273.15) .rename('gldas_temp'), falseCase: invalidImage }), falseCase: temperatureImage }) ); // 最终有效性检查 (服务器端方法): 如果 is_valid 等于1,则为有效图像 var isValid = ee.Number(temperatureImage.get('is_valid')).eq(1); // 裁剪并设置属性 return ee.Algorithms.If({ condition: isValid, trueCase: temperatureImage .clip(regionGeometry) .set({ 'year': year, 'data_source': temperatureImage.bandNames().get(0), 'is_valid': 1 }), falseCase: invalidImage.set('year', year) }); } ``` 注意:在最后一部分,我们使用`isValid`作为条件,它应该是当`is_valid`等于1时为1(真),否则为0(假)。而`ee.Algorithms.If`在条件为真(非0)时返回`trueCase`,否则返回`falseCase`。 另外,我们在最后设置`is_valid`属性时,有效图像设为1,无效图像在`invalidImage`中设为0。所以最后返回时,有效图像会保留,无效图像则返回一个只有属性`year`和`is_valid=0`的图像。 现在,我们提供完整的代码,并修改了这三处。 ## 完整代码 ```javascript // =============================================== // 京津冀地区温度数据提取完整解决方案 (修复服务器端逻辑操作问题) // =============================================== // 1. 正确获取京津冀区域几何体 function getRegionGeometry() { var chinaAdmin1 = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level1"); var beijing = chinaAdmin1.filter(ee.Filter.eq('ADM1_NAME', 'Beijing')); var tianjin = chinaAdmin1.filter(ee.Filter.eq('ADM1_NAME', 'Tianjin')); var hebei = chinaAdmin1.filter(ee.Filter.eq('ADM1_NAME', 'Hebei')); var mergedCollection = beijing.merge(tianjin).merge(hebei); var regionGeometry = mergedCollection.geometry().bounds(); return regionGeometry; } // 获取区域几何体 var regionGeometry = getRegionGeometry(); // 2. 温度数据源定义 var datasets = { modis_day: ee.ImageCollection("MODIS/061/MOD11A2").select('LST_Day_1km'), modis_night: ee.ImageCollection("MODIS/061/MOD11A2").select('LST_Night_1km'), era5: ee.ImageCollection("ECMWF/ERA5_LAND/MONTHLY").select('temperature_2m'), gldas: ee.ImageCollection("NASA/GLDAS/V021/NOAH/G025/T3H").select('Tair_f_inst') }; // 3. 温度数据处理函数 - 修复服务器端逻辑操作 function getAnnualTemperature(year) { var startDate = ee.Date.fromYMD(year, 1, 1); var endDate = startDate.advance(1, 'year'); // 定义无效图像标记 var invalidImage = ee.Image().set('is_valid', 0); // 尝试不同数据源 var modisDay = datasets.modis_day .filterDate(startDate, endDate) .filterBounds(regionGeometry); // 检查MODIS白天数据是否可用 var modisDayAvailable = modisDay.size().gt(0); // 处理MODIS数据 var temperatureImage = ee.Image( ee.Algorithms.If({ condition: modisDayAvailable, trueCase: modisDay.mean() .multiply(0.02).subtract(273.15) .rename('temp_day'), falseCase: invalidImage }) ); // 正确检查图像有效性 (服务器端方法): 如果 is_valid 不等于1,说明无效,需要尝试下一个数据源 var imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); // 如果MODIS不可用,尝试ERA5 temperatureImage = ee.Image( ee.Algorithms.If({ condition: imageValid, trueCase: ee.Algorithms.If({ condition: datasets.era5 .filterDate(startDate, endDate) .filterBounds(regionGeometry) .size().gt(0), trueCase: datasets.era5 .filterDate(startDate, endDate) .filterBounds(regionGeometry) .mean() .subtract(273.15) .rename('era5_temp'), falseCase: invalidImage }), falseCase: temperatureImage }) ); // 更新有效性检查 (服务器端方法) imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); // 如果ERA5不可用,尝试GLDAS temperatureImage = ee.Image( ee.Algorithms.If({ condition: imageValid, trueCase: ee.Algorithms.If({ condition: datasets.gldas .filterDate(startDate, endDate) .filterBounds(regionGeometry) .size().gt(0), trueCase: datasets.gldas .filterDate(startDate, endDate) .filterBounds(regionGeometry) .mean() .subtract(273.15) .rename('gldas_temp'), falseCase: invalidImage }), falseCase: temperatureImage }) ); // 最终有效性检查 (服务器端方法): 如果 is_valid 等于1,则为有效图像 var isValid = ee.Number(temperatureImage.get('is_valid')).eq(1); // 裁剪并设置属性 return ee.Algorithms.If({ condition: isValid, trueCase: temperatureImage .clip(regionGeometry) .set({ 'year': year, 'data_source': temperatureImage.bandNames().get(0), 'is_valid': 1 }), falseCase: invalidImage.set('year', year) }); } // 4. 时间范围处理 (2000-2023) var years = ee.List.sequence(2000, 2023); // 使用映射函数处理年份 var temperatureImages = years.map(function(year) { return getAnnualTemperature(year).set('year', year); }); // 过滤掉无效图像 (服务器端方法) var validImages = ee.ImageCollection(temperatureImages).filter( ee.Filter.eq('is_valid', 1) ); // 创建图像集合 var temperatureCollection = ee.ImageCollection(validImages); // 5. 可视化 var visParams = { min: -10, max: 30, palette: ['blue', 'cyan', 'green', 'yellow', 'red'] }; // 添加最新年份的温度图层 var latestTemp = temperatureCollection.filter( ee.Filter.eq('year', 2023) ).first(); Map.centerObject(regionGeometry, 6); Map.addLayer(latestTemp, visParams, '2023年平均温度'); // 6. 时间序列图表 // 计算区域平均温度 var chart = ui.Chart.image.series({ imageCollection: temperatureCollection, region: regionGeometry, reducer: ee.Reducer.mean(), scale: 5000, xProperty: 'year' }).setOptions({ title: '京津冀地区年平均温度变化 (2000-2023)', hAxis: {title: '年份'}, vAxis: {title: '温度 (°C)'}, lineWidth: 2, pointSize: 4 }); print(chart); // 7. 导出所有年份数据 // 使用批量导出方法 Export.image.toDrive({ image: temperatureCollection.toBands(), description: 'Annual_Temperature_Composite', folder: 'GEE_Temperature_Data', fileNamePrefix: 'temperature_composite', region: regionGeometry, scale: 1000, maxPixels: 1e13, crs: 'EPSG:4326', fileFormat: 'GeoTIFF' }); print('已创建复合图像导出任务'); print('脚本执行完成!'); ``` ## 错误修复总结 1. **问题原因**: - `ee.Algorithms.Not` 不是 GEE 中的有效函数。 - 之前的修复尝试使用了不存在的函数。 2. **解决方案**: - 使用 `ee.Number` 的 `neq` 方法替代逻辑非操作。 - 将 `ee.Algorithms.IsEqual(...)` 的比较结果转换为数字比较。 - 使用 `ee.Number(x).neq(y)` 实现“不等于”比较。 3. **修改点**: - 将三处有效性检查从 `ee.Algorithms.Not(ee.Algorithms.IsEqual(...))` 改为 `ee.Number(...).neq(1)` - 将最终有效性检查改为 `ee.Number(...).eq(1)` 此版本应能解决所有服务器端逻辑操作问题,并正确运行。 §§相关问题§§: 1. 在Google Earth Engine中如何处理条件判断和逻辑运算? 2. 如何优化GEE中的图像集合处理以提高性能? 3. 在GEE中导出大数据集的最佳实践是什么? 4. 如何调试Google Earth Engine脚本中的常见错误? </think> # 解决 "ee.Algorithms.Not is not a function" 错误 这个错误表明在 Google Earth Engine 中尝试使用了不存在的 `ee.Algorithms.Not` 方法。实际上,GEE 没有提供这个特定的逻辑操作方法,我们需要使用其他方式实现逻辑非操作。 ## 完整修复方案 ```javascript // =============================================== // 京津冀地区温度数据提取完整解决方案 (修复逻辑操作问题) // =============================================== // 1. 正确获取京津冀区域几何体 function getRegionGeometry() { var chinaAdmin1 = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level1"); var beijing = chinaAdmin1.filter(ee.Filter.eq('ADM1_NAME', 'Beijing')); var tianjin = chinaAdmin1.filter(ee.Filter.eq('ADM1_NAME', 'Tianjin')); var hebei = chinaAdmin1.filter(ee.Filter.eq('ADM1_NAME', 'Hebei')); var mergedCollection = beijing.merge(tianjin).merge(hebei); var regionGeometry = mergedCollection.geometry().bounds(); return regionGeometry; } // 获取区域几何体 var regionGeometry = getRegionGeometry(); // 2. 温度数据源定义 var datasets = { modis_day: ee.ImageCollection("MODIS/061/MOD11A2").select('LST_Day_1km'), modis_night: ee.ImageCollection("MODIS/061/MOD11A2").select('LST_Night_1km'), era5: ee.ImageCollection("ECMWF/ERA5_LAND/MONTHLY").select('temperature_2m'), gldas: ee.ImageCollection("NASA/GLDAS/V021/NOAH/G025/T3H").select('Tair_f_inst') }; // 3. 温度数据处理函数 - 使用正确的逻辑操作方法 function getAnnualTemperature(year) { var startDate = ee.Date.fromYMD(year, 1, 1); var endDate = startDate.advance(1, 'year'); // 定义无效图像标记 var invalidImage = ee.Image().set('is_valid', 0); // 尝试不同数据源 var modisDay = datasets.modis_day .filterDate(startDate, endDate) .filterBounds(regionGeometry); // 检查MODIS白天数据是否可用 var modisDayAvailable = modisDay.size().gt(0); // 处理MODIS数据 var temperatureImage = ee.Image( ee.Algorithms.If({ condition: modisDayAvailable, trueCase: modisDay.mean() .multiply(0.02).subtract(273.15) .rename('temp_day'), falseCase: invalidImage }) ); // 正确检查图像有效性 (使用数字比较) var imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); // 如果MODIS不可用,尝试ERA5 temperatureImage = ee.Image( ee.Algorithms.If({ condition: imageValid, trueCase: ee.Algorithms.If({ condition: datasets.era5 .filterDate(startDate, endDate) .filterBounds(regionGeometry) .size().gt(0), trueCase: datasets.era5 .filterDate(startDate, endDate) .filterBounds(regionGeometry) .mean() .subtract(273.15) .rename('era5_temp'), falseCase: invalidImage }), falseCase: temperatureImage }) ); // 更新有效性检查 (使用数字比较) imageValid = ee.Number(temperatureImage.get('is_valid')).neq(1); // 如果ERA5不可用,尝试GLDAS temperatureImage = ee.Image( ee.Algorithms.If({ condition: imageValid, trueCase: ee.Algorithms.If({ condition: datasets.gldas .filterDate(startDate, endDate) .filterBounds(regionGeometry) .size().gt(0), trueCase: datasets.gldas .filterDate(startDate, endDate) .filterBounds(regionGeometry) .mean() .subtract(273.15) .rename('gldas_temp'), falseCase: invalidImage }), falseCase: temperatureImage }) ); // 最终有效性检查 (使用数字比较) var isValid = ee.Number(temperatureImage.get('is_valid')).eq(1); // 裁剪并设置属性 return ee.Algorithms.If({ condition: isValid, trueCase: temperatureImage .clip(regionGeometry) .set({ 'year': year, 'data_source': temperatureImage.bandNames().get(0), 'is_valid': 1 }), falseCase: invalidImage.set('year', year) }); } // 4. 时间范围处理 (2000-2023) var years = ee.List.sequence(2000,
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值