用C语言实现可添加删除元素的数组(两种方式,数组和指针)

本文深入探讨了在C语言中如何使用数组和指针实现动态数组,包括添加、删除和输出元素的操作,提供了详细的代码示例和解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

——个人笔记

  • 这对于初学C的人来说,是一个比较有意思的问题。要运用到的知识点比较全面,方法也比较实用

数组思路

  • 这个只是个人思路,如果你想到更好的不妨试试。首先由于C没有动态数组,那么我们就声明一个int类型范围比较大的数组,比如 int array[1000]。那么我们要知道里面存放多少个元素,要怎么获取呢?直接用sizeof(array)/sizeof(array[0])是获取到这个数组的容量大小,而不是元素多少。那么我们要有一个标记,记录当前元素的个数(声明int len=0;)。添加就是我们要添加一个元素,就把array[len]=该元素,然后len++就实现了添加功能。删除就是查找数组(遍历数组)找到与要删除相同的元素那么就删除而且len--输出就是循环i从0开始,到i<len输出就行了。要实现一直能输入,只要把我们做好的功能放到一个死循环进行就可以了。

数组实现

  • 上面的思路懂了,可能还是一脸懵逼不知道怎么写。
    那么从最简单的入手,先定义我们需要的变量

    int array[1000] = { 0 };//我们要用的数组
    int len = 0;//标记,记录当前元素个数
    int choice;//我们要进行的操作
    int input;//输入增加或者删除的元素
    
    //这个是阐述这个编程的功能按键,放在这里是不想再下面写那么多。
    printf("请输入你要的操作\n--1--添加元素\n--2--删除元素\n--3--输出元素和有多少元素\n--4--退出程序\n");
    
  • 如果一开始漏了一些需要用到的变量的定义也无所谓,我们在实现的时候再补上就行。
    开始编写内容:

  • 要可以选择多种操作,我们可以想到分支(switch)那么我们就有一个整体框架了(退出操作要在死循环才要处理,比如输入4结束(while(1){if(choice==4)break;})或者在case 4:return;也行)

    switch (choice)
    		{
    		case 1:
    			printf("请输入要添加的元素:\n");
    			 //TODO 要进行添加操作
    		case 2:
    			printf("请输入要删除的元素:\n");
    			//TODO进行删除操作
    			break;
    		case 3:
    			printf("数组总共有%d个元素:\n", len);
    			//这里我就不详细讲了,查询操作
    			for (int i = 0; i < len; i++)
    			{
    				printf("%d ", array[i]);
    			}
    			printf("\n");
    			break;		 
    		default:
    			break;
    		}		 
    
  • 理解后,我们只要补充TODO的部分就行了
    添加元素:

    //放在cese 1下面
    scanf("%d", &input);
    array[len] = input;
    len++;
    
  • 删除元素:

    //放在case 2下面
    scanf("%d", &input);
    for (int i = 0; i < len; i++)
    {
    	if (array[i] == input)//检测到是要删除的元素
    	{
    		for(int j=i;j<len-1;j++)//把数组前移,覆盖了要删除的元素
    		{
    			array[j] = array[j + 1];
    		}
    		len--;//标记前移,相当于删除了最后一个位置
    		i--;//这个为什么要减呢?别急,下面会讲,先懂得上面数组和标记前移为啥能删除元素
    	}
    }
    printf("\n");
    

    上面为什么检测到要删除的元素,删除之后,需要把i也减去1呢?你可以看到大循环里面,我们结束条件是i<len,但是删除元素的时候(里面的循环)len会–,而我们当前检测到的位置已经变成了后面的元素了,所以要重新检测当前位置。你可以尝试一下不要i--;这一句,一般情况下还是正确的,只是如果出现连续相同的元素那么你就会出错,比如你连续添加了6个1,现在你按3输出数组,那么是1 1 1 1 1 1,然后你删除元素1,会怎么?再加上i--;,再运行试一下。你自己模拟一下你是计算机,用纸笔模拟一下哈哈!不理解再想想,完整代码应该不需要了吧,不懂再问!

指针思想

  • 虽然C没有动态数组,但是我们可以申请连续的空间,每次增加就重新申请,从而实现动态,其余思路和数组思路差不多一样。

指针实现

  • 同样我们先想一下要什么全局变量

    int *p = NULL;
    int size = 0; //记录长度
    int choice;
    
  • 整体框架

    while (1)
    	{
    		printf("请输入你要的操作\n--1--添加元素\n--2--删除元素\n--3--输出元素和有多少元素\n--4--退出程序\n");
    		scanf("%d", &choice);
    		switch (choice)
    		{
    		case 1:
    			insert();//插入
    			break;
    		case 2:		 
    			delert();//删除,为啥不命名delete,因为是关键词
    			break;
    		case 3:
    			printAll();//输出
    			break;
    		case 4:
    			return 0;
    		break;
    		default:
    			break;
    		}
    		 
    	}
    
  • 添加元素

    void insert()
    {
    	printf("请输入要添加的元素:\n");
    	int input;
    	scanf("%d", &input);
    	//申请空间要用realloc,因为malloc是用于第一次申请新的空间,而要改动就要用realloc
    	p = (int)realloc(p, sizeof(int)*(size+1));//先申请扩大再放入,这里理解一下就是
    	                                          //你要先申请空的位置才能放东西
    	*(p + size) = input;
    	size++;
    }
    
  • 删除元素

    void delert()
    {
    	printf("请输入要删除的元素:\n");
    	int input;
    	scanf("%d", &input);
    	for (int i = 0; i < size; i++)
    	{
    		if (*(p+i) == input)
    		{
    			for (int j = i; j < size - 1; j++)
    			{
    				*(p+j) = *(p+j + 1);
    			}
    			p= (int)realloc(p, sizeof(int)*(size - 1));//先移动再缩小,你要清理了东西
    			                                           //才能减少空间
    			size--;
    			i--;
    		}
    	}
    }
    
  • 输出元素

    void printAll()
    {
    	printf("数组总共有%d个元素:\n", size);
    	for (int i = 0; i < size; i++)
    	{
    		printf("%d ",*(p + i));
    	}
    	printf("\n");
    }
    
<think>好的,我现在需要帮用户解决如何用C语言通过指针实现合并两个有序数组的问题。用户明确要求使用指针示例代码,所以我得先回顾相关的知识。 首先,合并两个有序数组通常有两种方法:一种是创建一个临时数组,然后逐个比较元素,把较小的放入临时数组,最后复制回去。不过用户提供的引用中提到,比如引用[2]引用[3]都提到了双指针的方法,尤其是从后往前合并,这样可以在不使用额外空间的情况下完成任务,特别是当第一个数组有足够的空间时。例如,题目中的nums1数组可能有足够的容量,如LeetCode的88题,这种情况下从后往前比较可以避免覆盖原数据。 用户提到使用指针,所以我需要考虑如何用指针操作而不是数组下标。指针操作的话,需要移动指针来访问元素,同时注意边界条件。 根据引用[3]中的方法,双指针两个数组的末尾开始比较,较大的元素放到合并后的末尾。这样可以避免覆盖nums1中未处理的元素,特别是当nums1本身有足够空间时。这种方法不需要额外空间,效率也高。 现在需要将这种方法转化为C语言的代码。首先确定参数,比如两个数组arr1arr2,它们的大小mn。假设arr1有足够的空间容纳合并后的数组,总长度为m+n。例如,LeetCode的题目通常这样设定。 代码的大致步骤应该是: 1. 初始化三个指针:p1指向arr1的最后一个有效元素(即m-1位置),p2指向arr2的最后一个元素(n-1位置),p指向合并后的末尾(m+n-1位置)。 2. 从后往前遍历,比较p1p2所指的值,将较大的放到p的位置,然后相应指针前移。 3. 当其中一个数组处理完后,如果arr2还有剩余元素,需要复制到arr1的前面位置。 需要注意的是,如果使用指针的话,可能需要用指针变量来跟踪当前位置,而不是使用整数索引。例如,定义int *p1 = arr1 + m -1;,类似的,p2p也是如此。 然后,编写代码的时候要注意边界情况,比如其中一个数组为空,或者元素全部合并后另一个数组还有剩余元素。 根据引用[2]中的思路,如果使用临时数组的话需要malloc,但用户可能更希望不需要额外空间的解法,所以优先考虑从后往前的双指针方法。 现在,把这些思路转化为具体的代码。例如: void merge(int* nums1, int m, int* nums2, int n) { int *p1 = nums1 + m - 1; int *p2 = nums2 + n - 1; int *end = nums1 + m + n - 1; while (p1 >= nums1 && p2 >= nums2) { if (*p1 > *p2) { *end-- = *p1--; } else { *end-- = *p2--; } } // 处理剩余的nums2元素 while (p2 >= nums2) { *end-- = *p2--; } } 这样,代码利用了三个指针,从后往前合并,无需额外空间。同时,如果nums1的元素先处理完,剩下的nums2元素可以直接复制到nums1的前面。如果nums2先处理完,剩下的nums1元素已经在正确的位置,无需处理。 测试一下这个代码是否正确。例如,nums1 = [1,3,5,0,0,0], m=3, nums2 = [2,4,6], n=3。合并后应该得到[1,2,3,4,5,6]。代码中,p1指向5,p2指向6,比较后放入末尾,依次类推。最后如果p2还有剩余,比如当nums1处理完但nums2还有元素时,需要继续复制。 另外,需要考虑m或n为0的情况。例如,如果n=0,则不需要处理。代码中的循环会自动跳过,直接返回nums1。同样,如果m=0,则直接将nums2复制到nums1中。 用户可能需要示例代码,所以需要提供完整的函数实现,并注释说明。同时,确保指针操作正确,不会越界。 总结,正确的做法是使用三个指针,从后往前合并,这样可以高效且不需要额外空间,符合用户的需求。</think>以下是使用指针实现合并两个有序数组的C语言示例代码及详细说明: ```c #include <stdio.h> void merge(int* nums1, int m, int* nums2, int n) { // 初始化三个指针:分别指向nums1末尾、nums2末尾、合并后数组末尾 int* p1 = nums1 + m - 1; int* p2 = nums2 + n - 1; int* end = nums1 + m + n - 1; // 逆向比较填充(避免覆盖未处理的nums1元素) while (p1 >= nums1 && p2 >= nums2) { *end-- = (*p1 > *p2) ? *p1-- : *p2--; } // 处理剩余元素(只需要处理nums2剩余情况) while (p2 >= nums2) { *end-- = *p2--; } } // 测试代码 int main() { int nums1[6] = {1, 3, 5, 0, 0, 0}; int nums2[] = {2, 4, 6}; merge(nums1, 3, nums2, 3); printf("合并结果:"); for (int i = 0; i < 6; i++) { printf("%d ", nums1[i]); } return 0; } ``` 代码说明: 1. **指针初始化**:`p1`指向nums1最后一个有效元素,`p2`指向nums2最后一个元素,`end`指向合并后数组的末尾位置 2. **逆向合并**:通过`while`循环比较两个指针指向的元素,将较大值放入`end`位置,并移动对应指针 3. **剩余处理**:当nums1元素处理完后,若nums2仍有剩余元素,直接复制到nums1前端 实现原理: 该算法利用$O(1)$空间复杂度完成合并,时间复杂度为$O(m+n)$。通过从后向前遍历的方式,避免了正向合并需要移动元素的额外操作[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值