赞
踩
数据结构分为两种
1、物理结构(内存中如何存储的)
2、逻辑结构(是我们想象出来的)
线性表(逻辑上连续)包括顺序表、链表、栈、队列。
顺序表在物理上和逻辑上都是连续的(其实就是数组)
- struct static_Array_list
- {
- int arr[10];
- int size;
- };
存在的问题
1、数据类型无法改变
2、数组大小无法改变
所以引入动态顺序表。
- typedef int SLDataType;
- typedef struct dynamic_Array_list
- {
- SLDataType *arr;//定义数组指针
- size_t size;//有效数据个数
- size_t capacity//容量
- }ArrayList;
缺点
1、顺序表在尾插尾删上很方便,但是在头(中间)插头(中间)删上复杂度为O(n)
2、空间利用率不高,增容会有一定空间浪费(批量增容)
优点
1、内存连续,随机访问
2、缓存命中率高(因为内存连续,预加载时把一段数据加载到缓存中,如果内存不连续,则会进行多次加载来获取所需要的的数据)
- // 基本增删查改接口
- // 顺序表初始化
- void ArrayListInit(ArrayList* psl, size_t capacity);
- // 顺序表销毁
- void ArrayListDestory(ArrayList* psl);
- // 顺序表打印
- void ArrayListPrint(ArrayList* psl);
- // 检查空间,如果满了,进行增容
- void CheckCapacity(ArrayList* psl);
- // 顺序表尾插
- void ArrayListPushBack(ArrayList* psl, SLDataType x);
- // 顺序表尾删
- void ArrayListPopBack(ArrayList* psl);
- // 顺序表头插
- void ArrayListPushFront(ArrayList* psl, SLDataType x);
- // 顺序表头删
- void ArrayListPopFront(ArrayList* psl);
- // 顺序表查找
- int ArrayListFind(ArrayList* psl, SLDataType x);
- // 顺序表在pos位置插入x
- void ArrayListInsert(ArrayList* psl, size_t pos, SLDataType x);
- // 顺序表删除pos位置的值
- void ArrayListErase(ArrayList* psl, size_t pos);
总的来说顺序表比较简单,因为底层是可以动态开辟空间的数组,基本接口的实现网上已经有很多相关的内容,不在赘述。
1. 原地移除数组中所有的元素val,要求时间复杂度为O(N),空间复杂度为O(1)。
- //为了达到O(1)的空间复杂度(不能额外开辟数组长度大小的空间)
- //时间复杂度O(N)(只能遍历一次数组)
- //所以采用双指针的方法,用不重复的元素替换掉重复的元素
- //注意各种判断条件
- int removeElement(int* nums, int numsSize, int val){
- int head = 0;
- int end = numsSize-1;
- while(head<=end)//加=号的目的是防止最后双指针相遇,相遇点正好是要删除的数值
- {
- while(head<numsSize&&nums[head]!=val)
- {
- head++;
- }
- while(end>=0&&nums[end]==val)
- {
- end--;
- }
- if(head<end)
- {
- nums[head]=nums[end];
- head++;
- end--;
- }
- }
- return end+1;
- }
- //给排序数组元素去重
- //同样的,空间复杂度要求是O(1)
- //还是利用双指针的思想,从前往后替换
- //注意数组为空的情况
- int removeDuplicates(int* nums, int numsSize){
-
- if(numsSize==0)
- return 0;
- int head1 = 0;
- int head2 = 1;
- while(head2<=numsSize-1)
- {
- while(head2<=numsSize-1&&nums[head1] == nums[head2])
- {
- head2++;
- }
- if(head2<=numsSize-1)
- {
- nums[++head1] = nums[head2];
- }
- }
- return head1+1;
- }
- void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
-
- //开辟额外的空间
- int *tmp = (int*)malloc(sizeof(int)*(m+n));
- //三个索引
- int index1=0;
- int index2=0;
- int index=0;
- while(index1<m && index2<n)
- {
- if(nums1[index1]<nums2[index2])
- {
- tmp[index++]=nums1[index1];
- index1++;
- }
- else
- {
- tmp[index++]=nums2[index2];
- index2++;
- }
- }
- //下面是将尾部的元素拷贝过来,可以优化,采用尾指针的方式
- //自动判断谁的尾部还有剩下的元素
- for(int i=index1;i<m;i++)
- tmp[index++]=nums1[i];
- for(int i=index2;i<n;i++)
- tmp[index++]=nums2[i];
- //拷贝给nums1
- for(int i=0;i<index;i++)
- nums1[i]=tmp[i];
- //整体来说时间复杂度O(2n+m),空间复杂度O(n+m)//可以优化
- }
- //方法1.新建一个数组
- //该方法比较简单,但空间复杂度高O(N)
- void rotate(int* nums, int numsSize, int k){
-
- int* array_tmp = (int*)malloc(sizeof(int)*numsSize);
- k=k%numsSize;//值得注意的地方
- for(int i=0;i<k;i++)
- {
- array_tmp[i]=nums[numsSize-k+i];
- }
- for(int i = k;i<numsSize;i++)
- {
- array_tmp[i]=nums[i-k];
- }
- for(int i = 0;i<numsSize;i++)
- {
- nums[i] = array_tmp[i];
- }
- }
-
- //方法2.旋转数组
- //时间复杂度O(N),空间复杂度O(1)
- void Reverse(int* nums, int numsSize)
- {
- for(int i = 0; i < numsSize/2; i++)
- {
- int tmp = nums[i];
- nums[i] = nums[numsSize-i-1];
- nums[numsSize-i-1] = tmp;
- }
- }
- void rotate(int* nums, int numsSize, int k){
-
- k = k%numsSize;
- if(k!=0)//如果k==0,说明原来数组的没变
- {
- Reverse(nums,numsSize);
- Reverse(nums,k);
- Reverse(nums+k,numsSize-k);
- }
- }
- //逐位相加,然后逆转数组
- int* addToArrayForm(int* num, int numSize, int k, int* returnSize){
-
- *returnSize = 0;
- int* returnArray = (int*)calloc(fmax(10, numSize + 1),sizeof(int));
- while(k || numSize)
- {
- if(numSize)
- {
- returnArray[*returnSize] = returnArray[*returnSize] + num[numSize-1] + k%10;
- numSize--;
- }
- else
- {
- returnArray[*returnSize] = returnArray[*returnSize] + k%10;
- }
- if(returnArray[*returnSize] > 9)
- {
- returnArray[*returnSize] = returnArray[*returnSize]%10;
- returnArray[(*returnSize) + 1] = 1;
- if(!(k/10)&&!numSize)//防止最后一个数发生进位,数据的长度会增加
- (*returnSize)++;
- }
-
- k = k/10;
- (*returnSize)++;
- }
- for (int i = 0; i < (*returnSize) / 2; i++)
- {
- int tmp = returnArray[i];
- returnArray[i] = returnArray[(*returnSize) - 1 - i];
- returnArray[(*returnSize) - 1 - i] = tmp;
- }
- return returnArray;
- }
总的来说顺序表是非常基础的一种数据结构,用处也非常广泛,在后续的数据结构中也有很多衍生出来的结构是基于顺序表的。与之相反的一种数据结构是链表,链表和顺序表的特性恰恰相反,下篇文章共同学习线性表中的链表。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。