线性表之数组

本文介绍了C语言中数组的概念和整型数组长度的计算方法,详细讲解了使用qsort函数进行排序的过程,包括自定义比较函数的实现。同时,列举了数组、字符数组、字符串数组和结构体数组的排序示例。此外,还提到了两数之和、三数之和、删除有序数组重复项、移除元素、搜索插入位置、合并区间、合并两个有序数组以及杨辉三角等编程问题的解决方法。
摘要由CSDN通过智能技术生成

1.数组

数组(Array)是有序的元素序列。为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。  这些有序排列的同类数组元素的集合称为数组。

整型数组的长度:

int a[]  = {1 , 3 , 5 , 7};

int length = sizeof(a) / sizeof(int);

length即为数组a的长度。

C语言中对数组的排序的函数:

qsort函数,包含在C 标准库 #include<stdlib.h>中。

qsort(需要被排序的数组,数组元素个数,每个元素大小,排序函数名)

排序函数就是由qsort函数的使用者自己定义的两个元素排大小准则。

int compare(const void* e1, const void* e2)
{
    int* p1 = e1;
    int* p2 = e2;
    if (*p1 > *p2)
    {
        return 1;
    }
    else if (*p1 == *p2)
    {
        return 0;
    }
    else if (*p1 < *p2)
    {
        return -1;
    }
}

int compare(const void* e1, const void* e)
排序函数的参数类型 一定是const void*

const—可以使在函数运行的过程中 原数组的值不被改变

void—是为了提升函数普适性,强制规定函数参数为void*

函数返回类型规定int

int* p1 = e1;
int* p2 = e2;

void*指针不能直接使用,所以创建两个整形指针储存原指针(被排序元素什么类型就用什么指针)

  if (*p1 > *p2)
    {
        return 1;
    }
    else if (*p1 == *p2)
    {
        return 0;
    }
    else if (*p1 < *p2)
    {
        return -1;
    }
这部分则为使用者自己定义的比较大小准则,如果该情况为大于则返回一个>0的值,如果小于返回一个<0的值,如果等于,则返回0

具体例子:

数组排序:

#include<stdio.h>
#include<stdlib.h>
int compare(const void* e1, const void* e2)
{
    int* p1 = e1;
    int* p2 = e2;
    if (*p1 > *p2)
    {
        return 1;
    }
    else if (*p1 == *p2)
    {
        return 0;
    }
    else if (*p1 < *p2)
    {
        return -1;
    }
}
int main()
{
    int arr[10] = { 1,3,5,7,9,2,4,6,8,10 };
    qsort(arr, 10, 4, compare);
    for (int i = 0; i <= 9; i++)
    {
        printf("%d ", arr[i]);
    }
}

字符数组排序:

#include<stdio.h>
#include<stdlib.h>
int compare(const void* e1, const void* e2)
{
    char* p1 = e1;
    char* p2 = e2;
    if (*p1 > *p2)
    {
        return 1;
    }
    else if (*p1 == *p2)
    {
        return 0;
    }
    else if (*p1 < *p2)
    {
        return -1;
    }
}
int main()
{
    char arr[10] = { 'a','c','b','d','h','g','t','n' ,'w'};
    qsort(arr, 9, 1, compare);
    printf("%s", arr);
}

字符串排序:

#include<stdio.h>
#include<stdlib.h>
int compare(const void* e1, const void* e2)//规定按首字母顺序排序
{
    char* p1 = e1;
    char* p2 = e2;
    if (*p1 > *p2)
    {
        return 1;
    }
    else if (*p1 == *p2)
    {
        return 0;
    }
    else if (*p1 < *p2)
    {
        return -1;
    }
}
int main()
{
    char arr1[5] = "abc";
    char arr2[5] = "bcd";
    char arr3[5] = "cdf";
    char arr4[5] = "gnm";
    char* arr[4] = { arr1,arr2,arr3,arr4 };//定义了一个指针数组来存放四个字符串数组的指针(数组名为数组第一个元素地址)
    qsort(arr, 4, 4, compare);//每个元素均为指针,指针大小为4字节
    printf("%s %s %s %s", arr1,arr2,arr3,arr4);
}

结构体排序:

#include<stdio.h>
#include<stdlib.h>
struct stu
{
    int grade;
    char name[20];
    char sex[10];
};
int compare(const void* e1, const void* e2)//规定按成绩排序
{
    struct stu* p1 = e1;
    struct stu* p2 = e2;
    if (p1->grade > p2->grade)
    {
        return 1;
    }
    else if (p1->grade==p2->grade)
    {
        return 0;
    }
    else if (p1->grade < p2->grade)
    {
        return -1;
    }
}
 
int main()
{
    struct stu a = { 90,"zhangsan","man" };
    struct stu b = { 80,"lisi","man" };
    struct stu c = { 70,"wangwu","man" };
    struct stu arr[3] = { a,b,c };
    qsort(arr, 3, sizeof(a), compare);
    for (int i = 0; i <= 2; i++)
        printf("%d %s %s\n", arr[i].grade, arr[i].name, arr[i].sex);
}

【1】两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 :

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
int main(){
	int a[] = {2 , 7 , 11 , 15};
	int target = 9;
	int n = sizeof(a) / sizeof(int);
	for(int i = 0; i < n ; i++){
		for(int j = i + 1; j < n; j++){
			if(target == a[i] + a[j]){
                printf("[");
				printf("%d", i + 1);
                printf(",");
				printf("%d", j + 1);
                printf("]");
				break;
			}
		}
	}
}

【2】三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 :

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

先对数组进行排序,然后一层for循环遍历最小的数,循环内用双指针寻找另外两数
找到正确结果后再去重

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    int base=100;                                           //数组的初始长度,可更改
    int** a=(int**)malloc(sizeof(int*)*base);
    *returnColumnSizes=(int*)malloc(sizeof(int)*base);
    *returnSize=0;                                          //初始化
    int i,j,k=0,mid,right,temp;
    for(i=0;i<numsSize;i++){
        for(j=i+1;j<numsSize;j++){
            if(nums[j]<nums[i]){
                temp=nums[i];
                nums[i]=nums[j];
                nums[j]=temp;
            }
            else continue;
        }
    }                                                       //选择排序
    for(i=0;i<numsSize;i++){
        if(i>0&&nums[i]==nums[i-1]){continue;}              //对i向左去重,(向右会忽略-1,-1,2)
        mid=i+1;right=numsSize-1;                           //定义双指针
        while(mid<right){
            if(nums[i]+nums[mid]+nums[right]==0){
                a[*returnSize]=(int*)malloc(sizeof(int)*3); //每一个数组大小都为3
                (*returnColumnSizes)[*returnSize]=3;        //给申请的空间赋值
                a[*returnSize][0]=nums[i];
                a[*returnSize][1]=nums[mid];
                a[*returnSize][2]=nums[right];
                (*returnSize)++;                            //行自增		
                int num1=nums[mid],num2=nums[right];        //对mid,right去重
                while(nums[mid]==num1&&mid<right){mid++;}
                while(nums[right]==num2&&mid<right){right--;}    
                if(*returnSize==base){
                    base*=2;
                    a=(int**)realloc(a,sizeof(int*)*base);
                    *returnColumnSizes=(int*)realloc(*returnColumnSizes,sizeof(int)*base);
                }//如果二维数组的大小达到初始设定的行数,则进行空间扩容
            }//找到目标数组
            else if(nums[i]+nums[mid]+nums[right]<0)
                    mid++;
            else    right--;  
        }
    }//i遍历最小的数,mid从i+1开始,寻找中间的数,right为右指针
    return a;
}

【3】删除有序数组中的重复项

给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k 。

不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过

示例 :

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

前后比较,遇到不相同的项,则在数组对应的位置写入即可

int removeDuplicates(int* nums, int numsSize){
    int k = 0,i;
    for(i = 1; i < numsSize; i++){
        if(nums[i - 1] != nums[i])
        nums[++k] = nums[i]; //++k而不是k++,因为下标为0的元素一定在新数组中
    }
    return k + 1;  //k+1才是返回的长度
}

【4】移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

示例 :

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
int removeElement(int* nums, int numsSize, int val){
        int k = 0,i;
        for(int i = 0; i < numsSize; i++ ){
            if(val != nums[i]){
                nums[k++] = nums[i];
            }
        }
        return k;
}

【5】搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 :

输入: nums = [1,3,5,6], target = 5
输出: 2
int searchInsert(int* nums, int numsSize, int target){
    int left=0;
    int right=numsSize-1;//若左右闭区间,则需要将长度转化为数组形式,因正常长度0是没有意义的,但是0在数组中充当数字的索引。
    while(left<=right){//因为是左右均是闭区间,因此可以出现数字相等
        int middle=left+((right-left)/2);//防止溢出,其效果等同(left+right)/2
        if(nums[middle]<target){
            left=middle+1;
        }else if (nums[middle]>target){
            right=middle-1;
        }
        else{
            return middle;
        }
    }
    return right+1;//此时需要改变的数字应在right的右边,故加一
}
//复杂空间为O(long_n)一般是要用二分法处理。

【6】合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

示例 :

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

c++来做简单些

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        int n=intervals.size();
        vector<vector<int>>nums;
        sort(intervals.begin(),intervals.end());
        for(int i=0;i<n;i++){
            int L=intervals[i][0],R=intervals[i][1];
            if(nums.size()==0||nums.back()[1]<L){
                nums.push_back({L,R});
            }else{
                nums.back()[1]=max(nums.back()[1],R);
            }
        }
        return nums;
    }
};

【7】合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 :

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
#include <stdio.h>
#include <stdlib.h>

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
    // 开辟一个新数组,用来存放合并后的结果
    int* ret = (int*)malloc(sizeof(int) * (m + n));
    // 初始化三个指针,用来遍历三个数组
    int cur1 = 0, cur2 = 0, dest = 0;

    // 当其中一个遍历到数组的结尾,我们就结束循环
    while (cur1 < m && cur2 < n)
    {
        // 当第一个数组的元素比较小的时候,我们就加入合并后的数组
        if (nums1[cur1] <= nums2[cur2])
            ret[dest++] = nums1[cur1++];
        // 否则就将第二个元素加入到目标数组
        else
            ret[dest++] = nums2[cur2++];
    }

    // 下面两个循环只会执行一个,因为只会有一个数组还有剩余元素
    // 当第一个数组的元素有剩余的话,就会执行第一个循环
    while (cur1 < m)
        ret[dest++] = nums1[cur1++]; // 将数组的内容拷贝到合并后的数组中
    // 当第二个数组的元素有剩余的话,就会执行第二个循环
    while (cur2 < n)
        ret[dest++] = nums2[cur2++];

    // 将合并后的数组,放回第一个数组中去
    for (int i = 0; i < m + n; i++)
    {
        nums1[i] = ret[i];
    }

    // 释放辅助数组
    free(ret);
}

【8】杨辉三角

给定一个非负整数 numRows生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

示例 1:

输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]


/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int** generate(int numRows, int* returnSize, int** returnColumnSizes){
    int** ret = malloc(sizeof(int*)*numRows); //申请返回的指针空间
    *returnSize = numRows; //返回行数
    *returnColumnSizes = malloc(sizeof(int*)*numRows); //为每一列分配空间
    for(int i=0;i<numRows;i++)
    {
        ret[i] = malloc(sizeof(int)*(i+1));
        //分配每一行的个数
        (*returnColumnSizes)[i] = i + 1;
        //为第一个以及最后一个赋值
        ret[i][0] = 1;
        ret[i][i] = 1;
        
        for(int j=1;j<i;j++)
        {
            ret[i][j] = ret[i-1][j-1] + ret[i-1][j];
        }
    }

    return ret;
}

【9】杨辉三角||

给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

示例 1:

输入: rowIndex = 3
输出: [1,3,3,1]

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* getRow(int rowIndex, int* returnSize){ //returnSize 代表传出数组的长度
    *returnSize = rowIndex+1; //为returnSize赋值
    //由于返回是数组,故需要创建一个数组
    int* ret[rowIndex + 1];
    //循环遍历
    for(int i=0;i<=rowIndex;i++)
    {
        //为每一行申请空间
        ret[i] = malloc(sizeof(int)*(i+1));
        //每一行中首元素和尾元素为1
        ret[i][0] = ret[i][i] = 1;

        //循环为每一行其余元素赋值
        for(int j=1;j<i;j++)
        {
            ret[i][j] = ret[i-1][j] + ret[i-1][j-1];
        }
    }

    return ret[rowIndex]; //返回对应rowIndex行 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值