天津网站推广公司哪家好seo教程 seo之家
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums =[0,1,0,3,12]
输出:[1,3,12,0,0]
示例 2:
输入: nums =[0]
输出:[0]
提示:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
进阶:你能尽量减少完成的操作次数吗?
代码如下:
写了一个仿照java ArrayList的 可变长数组的数据结构。为了验证,就用它实现本题功能。
IntArrayList.h 头文件:
#ifndef INT_ARRAY_LIST_H
#define INT_ARRAY_LIST_H// 头文件添加跨语言支持
#ifdef __cplusplus
extern "C" {
#endif#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include <string.h>typedef int (*Compare)(int, int); // 比较函数,用于排序typedef struct {int* data;int size; // 当前长度,即有多少条数据。int capacity; // 实际数组长度
}IntArrayList;IntArrayList* CreateIntArrayList(int initialCapacity);void FreeIntArrayList(IntArrayList* list);void ClearIntArrayList(IntArrayList* list);// 获取指定索引处的数据,因为不修改结构体数据,所以参数list加const修饰
int GetIntArrayList(const IntArrayList* list, int pos);bool InsertIntArrayList(IntArrayList* list, int val, int pos);bool AddIntArrayList(IntArrayList* list, int val);bool SetIntArrayList(IntArrayList* list, int val, int pos);bool DeleteIntArrayList(IntArrayList* list, int pos);bool ContainsIntArrayList(const IntArrayList* list, int val);int SizeIntArrayList(const IntArrayList* list);void SortIntArrayList(IntArrayList* list, Compare compare);#ifdef __cplusplus
}
#endif#endif
相应的,在源文件IntArrayList.c中完成函数定义:
#include "IntArrayList.h"// 检查数组容量, 容量不够就扩容。 为隐藏内部函数,加static修饰
static bool ensureCapacity(IntArrayList* list) {if (list->size == list->capacity) { // 实际储存的数据量已经把数组撑满了。int newCapacity = list->capacity << 1; // 为降低扩容频率,每次容量增加1倍int* newData = (int*)realloc(list->data, newCapacity * sizeof(int)); // if (!newData) {fprintf(stderr, "Memory allocation failed\n");//exit(EXIT_FAILURE); // 内存分配失败时退出程序return false;}else {list->data = newData;list->capacity = newCapacity;}}return true;
}IntArrayList* CreateIntArrayList(int initialCapacity) {IntArrayList* list = (IntArrayList*)malloc(sizeof(IntArrayList)); // 堆分配if (list == NULL) {fprintf(stderr, "Memory allocation failed\n");exit(EXIT_FAILURE);}list->data = (int*)malloc(initialCapacity * sizeof(int));if (list->data == NULL) {fprintf(stderr, "Memory allocation failed\n");exit(EXIT_FAILURE); // 内存分配失败时退出程序}list->capacity = initialCapacity;list->size = 0;return list;
}bool AddIntArrayList(IntArrayList* list, int val) {return InsertIntArrayList(list, val, SizeIntArrayList(list));
}void FreeIntArrayList(IntArrayList* list) {free(list->data);list->data = NULL; // 将指针设置为NULL以避免悬挂指针问题。list->size = 0;list->capacity = 0;free(list);
}void ClearIntArrayList(IntArrayList* list) {list->size = 0;
}int GetIntArrayList(const IntArrayList* list, int pos) {if (pos >= list->size || pos < 0) {// 越界了fprintf(stderr, "out of index\n");exit(EXIT_FAILURE);}return list->data[pos];
}bool InsertIntArrayList(IntArrayList* list, int val, int pos) {if (!ensureCapacity(list))return false;if (pos < 0 || pos > list->size) {fprintf(stderr, "InsertIntArrayList, out of index\n");printf("InsertIntArrayList, out of index , pos: %d, size: %d \n", pos, list->size);return false;}if (pos == list->size) {// 添加在最后,无需移动其他数据位置list->data[pos] = val;list->size++;return true;}// 在pos索引处插入数据,其他数据需要往后移动.// 先利用memmove函数移动数组中元素memmove(&list->data[pos + 1], &list->data[pos], (list->size - pos) * sizeof(int));list->data[pos] = val;list->size++;return true;
}bool SetIntArrayList(IntArrayList* list, int val, int pos) {if (pos < 0 || pos >= list->size) {fprintf(stderr, "out of index\n");return false;}list->data[pos] = val;return true;
}bool DeleteIntArrayList(IntArrayList* list, int pos) {if (pos < 0 || pos >= list->size) {fprintf(stderr, "out of index\n");return false;}if (pos == list->size - 1) {// 移动的是最后一个list->size--;return true;}// 将索引pos以及之后所有元素向前移动一个memmove(&list->data[pos], &list->data[pos + 1], (list->size - pos - 1) * sizeof(int));list->size--;return true;
}bool ContainsIntArrayList(const IntArrayList* list, int val) {for (int i = 0; i < list->size; i++) {if (list->data[i] == val)return true;}return false;
}int SizeIntArrayList(const IntArrayList* list) {return list->size;
}void SortIntArrayList(IntArrayList* list, Compare compare) {if (!list || list->size < 2)return;if (!compare) {printf("没传比较函数!\n");return;}// 先随便想个排序,用冒泡,后面优化为插入法或其他排序方法int temp;for (int i = 0; i < list->size - 1; i++) {// 提前退出冒泡循环的标志位int swapped = 0;for (int j = 0; j < list->size - 1 - i; j++) {if (compare(list->data[j], list->data[j+1]) > 0){temp = list->data[j];list->data[j] = list->data[j+1];list->data[j + 1] = temp;swapped = 1; // 表示发生了交换}}// 如果没有数据交换,数组已经有序,不需要再继续执行循环if (!swapped) {break;}}
}
代码:
#include <stdio.h>
#include <stdlib.h>
#include "IntArrayList.h"int compareFunZeroToLast(int a, int b) { // 目的是排序时把0排到最后if (a == 0 && b != 0)return 1;return 0;
}void moveZeroes(int* nums, int numsSize) { // LeeCode283. 移动零IntArrayList* list = CreateIntArrayList(numsSize); for (int i = 0; i < numsSize; i++) {if (!AddIntArrayList(list, nums[i])) {fprintf(stderr, "Failed to add element %d\n", nums[i]);FreeIntArrayList(list);return;}}SortIntArrayList(list, compareFunZeroToLast); // 关键是排序for (int i = 0; i < numsSize; i++) {nums[i] = GetIntArrayList(list, i); // 保存最终结果}
}
测试代码:
void testLeeCode283() {int nums[] = {0, 1, 0, 3, 12};moveZeroes(nums, sizeof(nums) / sizeof(nums[0]));printf("结果: \n");for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {printf("%d \n", nums[i]);}
}
打印:
ok。结果正确。
提交到LeeCode,因为LeeCode不能提交多个文件,所以代码合到一起,这样提交:
int compareFunZeroToLast(int a, int b) { // 目的是排序时把0排到最后if (a == 0 && b != 0)return 1;return 0;
}typedef int (*Compare)(int, int); // 比较函数,用于排序typedef struct {int* data;int size; // 当前长度,即有多少条数据。int capacity; // 实际数组长度
}IntArrayList;// 检查数组容量, 容量不够就扩容。 为隐藏内部函数,加static修饰
static bool ensureCapacity(IntArrayList* list) {if (list->size == list->capacity) { // 实际储存的数据量已经把数组撑满了。int newCapacity = list->capacity << 1; // 为降低扩容频率,每次容量增加1倍int* newData = (int*)realloc(list->data, newCapacity * sizeof(int)); // if (!newData) {fprintf(stderr, "Memory allocation failed\n");//exit(EXIT_FAILURE); // 内存分配失败时退出程序return false;}else {list->data = newData;list->capacity = newCapacity;}}return true;
}IntArrayList* CreateIntArrayList(int initialCapacity) {IntArrayList* list = (IntArrayList*)malloc(sizeof(IntArrayList)); // 堆分配if (list == NULL) {fprintf(stderr, "Memory allocation failed\n");exit(EXIT_FAILURE);}list->data = (int*)malloc(initialCapacity * sizeof(int));if (list->data == NULL) {fprintf(stderr, "Memory allocation failed\n");exit(EXIT_FAILURE); // 内存分配失败时退出程序}list->capacity = initialCapacity;list->size = 0;return list;
}void FreeIntArrayList(IntArrayList* list) {free(list->data);list->data = NULL; // 将指针设置为NULL以避免悬挂指针问题。list->size = 0;list->capacity = 0;free(list);
}void ClearIntArrayList(IntArrayList* list) {list->size = 0;
}int GetIntArrayList(const IntArrayList* list, int pos) {if (pos >= list->size || pos < 0) {// 越界了fprintf(stderr, "out of index\n");exit(EXIT_FAILURE);}return list->data[pos];
}bool InsertIntArrayList(IntArrayList* list, int val, int pos) {if (!ensureCapacity(list))return false;if (pos < 0 || pos > list->size) {fprintf(stderr, "InsertIntArrayList, out of index\n");printf("InsertIntArrayList, out of index , pos: %d, size: %d \n", pos, list->size);return false;}if (pos == list->size) {// 添加在最后,无需移动其他数据位置list->data[pos] = val;list->size++;return true;}// 在pos索引处插入数据,其他数据需要往后移动.// 先利用memmove函数移动数组中元素memmove(&list->data[pos + 1], &list->data[pos], (list->size - pos) * sizeof(int));list->data[pos] = val;list->size++;return true;
}bool SetIntArrayList(IntArrayList* list, int val, int pos) {if (pos < 0 || pos >= list->size) {fprintf(stderr, "out of index\n");return false;}list->data[pos] = val;return true;
}bool DeleteIntArrayList(IntArrayList* list, int pos) {if (pos < 0 || pos >= list->size) {fprintf(stderr, "out of index\n");return false;}if (pos == list->size - 1) {// 移动的是最后一个list->size--;return true;}// 将索引pos以及之后所有元素向前移动一个memmove(&list->data[pos], &list->data[pos + 1], (list->size - pos - 1) * sizeof(int));list->size--;return true;
}bool ContainsIntArrayList(const IntArrayList* list, int val) {for (int i = 0; i < list->size; i++) {if (list->data[i] == val)return true;}return false;
}int SizeIntArrayList(const IntArrayList* list) {return list->size;
}bool AddIntArrayList(IntArrayList* list, int val) {return InsertIntArrayList(list, val, SizeIntArrayList(list));
}void SortIntArrayList(IntArrayList* list, Compare compare) {if (!list || list->size < 2)return;if (!compare) {printf("没传比较函数!\n");return;}// 先随便想个排序,用冒泡,后面优化为插入法或其他排序方法int temp;for (int i = 0; i < list->size - 1; i++) {// 提前退出冒泡循环的标志位int swapped = 0;for (int j = 0; j < list->size - 1 - i; j++) {if (compare(list->data[j], list->data[j+1]) > 0){temp = list->data[j];list->data[j] = list->data[j+1];list->data[j + 1] = temp;swapped = 1; // 表示发生了交换}}// 如果没有数据交换,数组已经有序,不需要再继续执行循环if (!swapped) {break;}}
}void moveZeroes(int* nums, int numsSize) {IntArrayList* list = CreateIntArrayList(numsSize);for (int i = 0; i < numsSize; i++) {if (!AddIntArrayList(list, nums[i])) {fprintf(stderr, "Failed to add element %d\n", nums[i]);FreeIntArrayList(list);return;}}SortIntArrayList(list, compareFunZeroToLast);for (int i = 0; i < numsSize; i++) {nums[i] = GetIntArrayList(list, i);}
}
结果:
ok,性能稍差而已。
想起来忘记释放内存了,内存管理是真烦人哪, moveZeroes函数重新贴一下代码:
void moveZeroes(int* nums, int numsSize) { // LeeCode283. 移动零IntArrayList* list = CreateIntArrayList(numsSize);for (int i = 0; i < numsSize; i++) {if (!AddIntArrayList(list, nums[i])) {fprintf(stderr, "Failed to add element %d\n", nums[i]);FreeIntArrayList(list);return;}}SortIntArrayList(list, compareFunZeroToLast);for (int i = 0; i < numsSize; i++) {nums[i] = GetIntArrayList(list, i);}FreeIntArrayList(list); // 别忘记释放内存!
}
总结,编码中遇过好几个错误。 1、 函数不要返回局部指针变量,局部指针变量,存储在 栈内存 ,若该地址在函数退出后会被回收,导致出现野指针。必须使用 malloc
在堆上分配内存。 2、若c、c++混合编程,头文件需要加跨语言支持。 3、记得释放内存