顺序表C语言

线性表

线性表是n个具有相同特性的数据元素的有限序列,是一种实际中广泛使用的数据结构,常见的线性表有顺序表、链表、栈、队列、字符串
线性表在逻辑上是线性结构,即连续的一条直线,但在物理上不一定连续,线性表在物理上存储时,通常以数组和链式结构的形式存储
在这里插入图片描述
在这里插入图片描述

顺序表及其特点

数组缺陷:定义数组时必须指定数组大小,但是如果指定的大小不能满足使用空间需求时,就会有问题
顺序表含义及特点:顺序表本质是数组,是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储,在数组上完成数据的增删查改,顺序表要从左往右连续存储数据。顺序表的逻辑结构和物理结构都是连续的
2.顺序表分类:顺序表有两种,包括静态顺序表和动态顺序表
1、静态顺序表:使用定长数组存储元素。

//顺序表的静态存储
#define N 7
typedef int SLDataType
typedef struct SeqList
{
	SLDataType array[N];//定长数组
	size_t size;//有效数据的个数
}SeqList;

在这里插入图片描述
(2)动态顺序表:使用动态开辟的数组存储。

typedef struct SeqList
{
	SLDataType* array;//指向动态开辟的数组
	size_t size;//有效数据的个数
	size_t capacity;//容量
}SeqList;

在这里插入图片描述
3. 顺序表缺陷:
(1)动态增容有性能消耗。
(2)当头部插入数据时,需要挪动数据

顺序表的实现

静态顺序表容量是固定的,因此静态顺序表不实用。那么如何实现动态顺序表呢?

dynamicSequenceTable.h

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;
	int size;
	int capacity;
}SeqList,SEQ;
//初始化顺序表
void SeqListInit(SeqList* seq);
//销毁
void SeqListDestroy(SeqList* seq);
//打印
void print(SqList* seq);
//扩容
void SeqCheckCapacity(SeqList* seq);
//尾插
void SeqListPushBack(SeqList* seq,SLDataType x);
//头插
void SeqListPushFront(SeqList* seq,SLDataType x);
//尾删
void SeqListPopBack(SeqList* seq);
//头删
void SeqListPopFront(SeqList* seq);
//查找
int SeqListFind(SeqList* seq);
//某一位插入数据
void SeqListInsert(SeqList* seq,int pos,SLDataType x)
//某一位置删除数据
void SeqListErase(SeqList* seq,int num);
//某一位置删除数据
void SeqListModify(SeqList* seq,int pos,SeqDataType x);

dynamicSequenceTable.c

#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include "dynamicSequenceTable.h"
//初始化顺序表
void SeqListInit(SeqList* seq)
{
	seq->a=NULL;
	seq->size=0;
	seq->capacity=0;
}
//销毁
void SeqListDestroy(SeqList* seq)
{
	free(seq->a);
	seq->a=NULL
	seq->size=0;
	seq->capacity=0;
}
//打印
void print(SqList* seq)
{
	int i=0;
	for(i=0;i<seq->size;i++)
	{
		printf("%d ",seq->a[i]);
	}
	printf("\n");
}
//扩容
void SeqCheckCapacity(SeqList* seq)
{
	if(seq->size==seq->capacity)
	{
		int newCapacity=seq->capacity==0?4:seq->capacity*2;
		SLDataType* new = (SLDataType*)realloc(seq->a,sizeof(SLDataType)*newCapacity);
		if(new==NULL)
		{
			printf("realloc error:");
			return;
		}
		seq->a=new;
		seq->capacity=newcapacity;
	}
}
//尾插
void SeqListPushBack(SeqList* seq,SLDataType x)
{
	SeqCheckCapacity(seq);
	seq->a[size]=x;
	seq->size++;
}
//头插
void SeqListPushFront(SeqList* seq,SLDataType x)
{
	SeqCheckCapacity(seq);
	int end=seq->size-1;
	while(end>=0)
	{
		seq->a[end+1]=seq->a[end];
		end--;
	}
	seq->a[0]=x;
	seq->size++;
}
//尾删
void SeqListPopBack(SeqList* seq)
{
	seq->size--;
}
//头删
void SeqListPopFront(SeqList* seq)
{
	int begin=0;
	while(begin<size)
	{
		seq->a[begin]=seq->q[begin+1];
		begin++;
	}
	seq->size--;
}
//查找
int SeqListFind(SeqList* seq,SLDataType x)
{
	SeqCheckCapacity(seq);
	int i=0;
	for(i=0;i<seq->size;i++)
	{
		if(seq->a[i]==x)
		{
			return i;
		}
	}
	return -1;
}
//某一位插入数据
void SeqListInsert(SeqList* seq,int pos,SLDataType x)
{
	SeqCheckCapacity(seq);
	int i=seq->size-1;
	while(i>=pos)
	{
		seq->a[i+1]=seq->a[i];
		i--;
	}
	seq->a[pos]=x;
	seq->size++;
}
//某一位置删除数据
void SeqListErase(SeqList* seq,int num)
{
	int i=pos;
	for(i;i<seq->size;i++)
	{
		seq->a[i]=seq->a[i+1];
	}
	seq->size--;
}
//修改某一位置数据
void SeqListModify(SeqList* seq,int pos,SeqDataType x)
{
	pq->a[pos] = x;
}

顺序表的应用

https://leetcode-cn.com/problems/add-to-array-form-of-integer/
数组形式的整数相加
对于非负整数 X 而言,X 的数组形式是每位数字按从左到右的顺序形成的数组。例如,如果 X = 1231,那么其数组形式为 [1,2,3,1]。给定非负整数 X 的数组形式 A,返回整数 X+K 的数组形式。示例:
输入:A = [9,9,9,9,9,9,9,9,9,9], K = 1
输出:[1,0,0,0,0,0,0,0,0,0,0]
解释:9999999999 + 1 = 10000000000
分析:
1、不确定数组和数字相加的结果会不会产生进位,因此要用malloc为新数组分配空间,大小为数组和数字较大位数值+1
2、进位如何解决?将数组和数字对应位及进位相加的和如果比10大,那么该位结果就要-10,进位置1
3、对于(2)中的结果如何存放?如果将结果在新数组中从最右侧往最左侧存放,那么有可能相加的最终结果最高位没有产生进位,这就会导致新数组最高位为0,还需要将其他位顺次向前挪,如下图左图所示。因此应从最左侧往最右侧存放,记录新数组实际使用的长度,计算完毕再将数组逆序
在这里插入图片描述

#define  _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
#include<stdlib.h>
int* addToArrayForm(int* A, int ASize, int k, int* returnSize) 
{
	int kSize = 0;
	int num = k;
	
	//计算数字k的位数
	while (num)
	{
		num /= 10;
		kSize++;
	}
 
	//新数组大小为:max{数组长度,数字位数}+1,+1的原因是并不知道相加的最高位会不会有进位
	int len = ASize > kSize ? ASize + 1 : kSize + 1;
	
	//为新数组malloc动态开辟空间
	int* retArr = (int*)malloc(sizeof(int) * len);
	
	if (retArr == NULL)
	{
		return NULL;
	}
	
	int Ai = ASize - 1;//数组下标
	int Ki = 0;//数字从低到高第i位
	int next = 0;//进位
	int reti = 0;//新数组最终长度
	
	//只要数组和数字有一个没走完就进while循环
	while (Ai >= 0 || Ki < kSize)
	{
		int aval = 0;
		
		if (Ai >= 0)
		{
			aval = A[Ai--];//取数组最右端一位
		}
 
 
		int kval = k % 10;//取数字最低位
		k /= 10;
		Ki++;
 
		//相加和
		int ret = aval + kval + next; 
 
		//判断相加和是否产生进位
		if (ret >= 10)
		{
			next = 1;
			ret -= 10;
		}
		else
		{
			next = 0;
		}
 
		//注意此时将结果在新数组中按照从左到右的顺序存储,因此执行结束后,新数组需要逆置
		retArr[reti++] = ret;
	}
 
	//最高位相加的结果如果进位是1,那么还需将1存储在新数组最高位
	if (next == 1)
	{
		retArr[reti++] = 1;
	}
	
	//逆置新数组
	int begin = 0, end = reti - 1;
	while (begin < end)
	{
		int temp = retArr[begin];
		retArr[begin] = retArr[end];
		retArr[end] = temp;
		begin++;
		end--;
	}
 
	*returnSize = reti;
	return retArr;
	
}
int main()
{
	int array[] = { 9,9,9,9,9 };
	int len = sizeof(array) / sizeof(array[0]);
	int* p = array;
	int number = 999;
	int newlen = 0;
	
	int *p1 = addToArrayForm(array, len, number, &newlen);
	
	int i = 0;
	for (i = 0; i < newlen; i++)
	{
		printf("%d ", *(p1 + i));
	}
	return 0;
}

2.力扣网- 合并两个有序数组
给你两个按非递减顺序排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你合并 nums2 到 nums1 中,使合并后的数组同样按非递减顺序排列
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

分析:1)nums1长度为m+n,无需开辟新数组。

(2)从数组左侧开始比较还是从数组右侧开始比较?如果从左侧开始比较,如果nums2的数据值<nums1的数据值,那么nums2的数据值放在nums1的对应位上,nums1的数据就会被覆盖,找不回来了,如下图所示。因此要从数组右侧向左开始比较。
在这里插入图片描述
(3)什么时候比较结束?nums1和nums2有一个走完就不用比较了,因此进入循环的判断条件是nums1和nums2的下标同时要>=0,当有一个不满足条件时,表明有一个数组走完了。此时如果是nums1走完了,那么就要把nums1剩下的数据直接拷贝到nums1前面剩下的几个位置中;如果是nums2走完了,那么就不用动,因为这就说明nums1剩下的没走的那几个数据比nums2的数据都小
在这里插入图片描述

#define  _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) 
{
	int end1 = m - 1;
	int end2 = n - 1;
	int end = m + n - 1;
 
	//从右侧开始比较nums1和nums2的数据值,将较大者放在nums1数组的最右侧
	while (end1 >= 0 && end2 >= 0)
	{
		if (nums1[end1] > nums2[end2])
		{
			nums1[end--] = nums1[end1--];
		}
		else
		{
			nums1[end--] = nums2[end2--];
		}
		 
	}
 
	//有一个数组走完,如果是nums2没走完,需要将nums2剩余数据拷贝到nums1前面位置中
	//如果是nums1没走完,不用动,因为nums1剩下的数据是最小的,本身就在nums1中
	while (end2 >= 0)
	{
		nums1[end--] = nums2[end2--];
	}
}
 
int main()
{
	int arr1[] = { 2,3,6,0,0,0,0};
	int len1 = sizeof(arr1) / sizeof(arr1[0]);
 
	int arr2[] = {1,2,5,7};
	int len2 = sizeof(arr2) / sizeof(arr2[0]);
	
	merge(arr1, len1, 3, arr2, len2, len2);
	
	int i = 0;
	for (i = 0; i < len1; i++)
	{
		printf("%d ", arr1[i]);
	}
}

3力扣网-轮转数组
给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。要求空间复杂度O(1)
示例:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
分析:有2种解法可以让空间复杂度为O(1):

(1)先实现旋转一次,再对旋转一次的方法执行旋转k次
在这里插入图片描述

#define  _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
void rotate(int* nums, int numsSize,int k)
{
 
	int i = 0;
	int end = numsSize;
 
	//旋转次数>数组长度,旋转次数需要对数组长度取模
	k %= numsSize;
	for (i = 0; i < k; i++)
	{
		//将最后一个元素保存下来
		int temp = nums[numsSize - 1];
		int j = 0;
 
		//一次向右旋转,将其余元素依次向后挪动
		for (j = numsSize - 2; j >= 0; j--)
		{
			nums[j + 1] = nums[j];
		}
 
		//把最后一个元素放在数组首元素的位置
		nums[0] = temp;
	}
 
}
 
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int len = sizeof(arr) / sizeof(arr[0]);
	
	int k = 6;
	
	rotate(arr, len, k);
 
	int i = 0;
	for (i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);
	}
	
	return 0;
}

(2)三步翻转法:将前k个元素进行翻转,再将后面len-k个元素进行翻转,最后整体翻转。
在这里插入图片描述

#define  _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>
 
//实现从起始位置到结束位置的翻转
void reverse(int* nums, int begin, int end)
{
	//起始位置与结束位置逐一对调
	while (begin < end)
	{
		int temp = nums[begin];
		nums[begin] = nums[end];
		nums[end] = temp;
		begin++;
		end--;
	}
}
 
void rotate(int* nums, int numsSize, int k) 
{
	reverse(nums, 0, k - 1);//翻转前k个元素
	reverse(nums, k, numsSize - 1);//翻转后len-k个元素
	reverse(nums, 0, numsSize - 1);//整体翻转
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int len = sizeof(arr) / sizeof(arr[0]);
 
	int k = 3;
 
	rotate(arr, len, k);
	int i = 0;
	for (i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);
	}
 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值