数据结构(C语言)2.线性表——顺序表

本文介绍顺序表的数据结构实现,包括动态顺序表的定义、初始化、销毁等操作,以及尾插、尾删、头插、头删等接口函数。此外,还提供了查找、插入、删除等实用功能,并通过三个示例展示了其应用。

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

1.顺序表的实现

//#include<stdio.h>
//#define N 100
//typedef int SLDataType;
//
////静态顺序表 
//typedef struct SeqList
//{
//	SLDataType a[N];
//	int size;  //表示数组中存储了多少个数组
//	
// }SL;
// 
// 
////接口函数 --命名风格是跟着STL走的 
//void SeqListInit(SL* ps);       //初始化 
//
////静态表特点:如果满了就不让插入  缺点:很难确定多少空间合适 
//void SeqListPushBack(SL* ps,SLDataType x);   //尾插 
//void SeqListPopBack(SL* ps);                 //尾删 
//void SeqListPushFront(SL* ps,SLDataType x);  //头插 
//void SeqListPoPFront(SL* ps);  //头删 
////……

#include<stdio.h>
#include<stdlib.h> 
#include<assert.h>
typedef int SLDataType;

//动态顺序表 
typedef struct SeqList
{
	SLDataType* a;
	int size;     //表示数组中存储了多少个数据 
	int capacity; //表示数组实际能存数据的容量空间是多少 (单位是数据个数) 
	
}SL;
 
//打印函数
void SeqListPrint(SL* ps)
{
	for(int i=0;i<ps->size;i++)
	{
		printf("%d ",ps->a[i]);
	}
	printf("\n");
} 
 
 
//接口函数 --命名风格是跟着STL走的 
void SeqListInit(SL* ps)       //初始化
{
	ps->a = NULL;
	ps->size = ps->capacity = 0;
} 

//销毁顺序表 
void SeqListDerstory(SL* ps)
{
	free(ps->a);
	ps->a = NULL; 
	ps->capacity=ps->size=0;
} 

void SeqListCheckCapacity(SL* ps)
{
	//如果没有空间或空间不足,那么我们就扩容 
	//realloc函数返回的是void*类型的指针
	//第一个参数是先前开辟内存块的指针,第二个参数是新的字节数,而不是新增的字节数
	//使用realloc函数的方法是:一个新的指针变量=(数据类型*)realloc(先前指针,新字节数) 
	if(ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0?4: ps->capacity*2;
		SLDataType* tmp = (SLDataType*)realloc(ps->a,newcapacity*sizeof(SLDataType));
		if(tmp==NULL)
		{
			printf("realloc fail\n");
			exit(-1); //退出函数  异常退出 
		}
		
		ps->a=tmp;
		ps->capacity=newcapacity;
	}
}

void SeqListPushBack(SL* ps,SLDataType x)   //尾插 尾部进行数据 
{
    SeqListCheckCapacity(ps);
	
	ps->a[ps->size] = x;
	ps->size++;
} 



void SeqListPopBack(SL* ps)            //尾删
{
//	//防止越界 
//	//方法一  温柔处理 
//	if(ps->size>0)
//	{
//		//ps->a[ps->size-1] = 0; 不影响 
//	      ps->size--;
//	}
    //方法二 暴力处理 
	assert(ps->size>0); //断言 如果小于或等于0就终止程序,并告知我们断言失败 
	ps->size--; 
  
	
}

 
void SeqListPushFront(SL* ps,SLDataType x)  //头插
{
	SeqListCheckCapacity(ps);
	
	//挪动数据 
	int end = ps->size-1;
	while(end>=0)
	{
		ps->a[end+1] = ps->a[end];
		--end;
	}
	ps->a[0] = x;
	ps->size++;
}
 
 
void SeqListPoPFront(SL* ps)  //头删
{
	assert(ps->size>0);
	
	int begin = 1;
	while(begin < ps->size)
	{
		ps->a[begin-1] = ps->a[begin];
		++begin;
	}
	
	ps->size--;
} 


//查找这个值的位置下标,没有找到返回-1 
int SeqListFind(SL* ps,SLDataType x)
{
	for(int i=0;i<ps->size;i++)
	{
		if(ps->a[i]==x)
		{
			return i;
		}
	}
	return -1;
}

//在pos指定位置插入X 
void SeqListInsert(SL* ps,int pos,SLDataType x)
{
//	//温柔 
//	if(pos>ps->size||pos<0)
//	{
//		printf("pos invalid\n");
//		return;
//	}
    
    //暴力的方式 
	assert(pos<=ps->size&&pos>=0); 
	
	SeqListCheckCapacity(ps);
	
	int end = ps->size-1;  
	while(end>=pos)
	{
		ps->a[end+1]=ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	++ps->size;
} 

//在pos指定位置删除数据 
void SeqListErase(SL* ps,int pos)
{
	 //暴力的方式 
	assert(pos<ps->size&&pos>=0); 
	
	int begin = pos;   
	while(begin<ps->size)
	{
		ps->a[begin]=ps->a[begin+1];
		++begin;
	}
	--ps->size;
} 


//……



void TestSeqList1()
{
	SL s1;
	SeqListInit(&s1);
	
	SeqListPushBack(&s1,1);
	SeqListPushBack(&s1,2);
	SeqListPushBack(&s1,3);
	SeqListPushBack(&s1,4);
	SeqListPushBack(&s1,5);
	
	SeqListPrint(&s1);
	
	SeqListPopBack(&s1);
	SeqListPrint(&s1);
	
	
	SeqListDerstory(&s1);
}

void TestSeqList2()
{
	SL s1;
	SeqListInit(&s1);
	
	SeqListPushBack(&s1,1);
	SeqListPushBack(&s1,2);
	SeqListPushBack(&s1,3);
	SeqListPushBack(&s1,4);
	SeqListPushBack(&s1,5);
	
	SeqListPrint(&s1);
	
	SeqListPushFront(&s1,10);
	SeqListPushFront(&s1,20);
	SeqListPushFront(&s1,30);
	SeqListPushFront(&s1,40);
	
	SeqListPrint(&s1);
	
	SeqListPoPFront(&s1);
	SeqListPrint(&s1);
	
	SeqListDerstory(&s1);
}

void TestSeqList3()
{
	SL s1;
	SeqListInit(&s1);
	
	SeqListPushBack(&s1,1);
	SeqListPushBack(&s1,2);
	SeqListPushBack(&s1,3);
	SeqListPushBack(&s1,4);
	SeqListPushBack(&s1,5);
	
	SeqListPrint(&s1);
	
	printf("%d\n",SeqListFind(&s1,3));
	printf("%d\n",SeqListFind(&s1,0));
	
	SeqListInsert(&s1,2,0);
	SeqListPrint(&s1);
	
	SeqListErase(&s1,3);
	SeqListPrint(&s1);
		
	SeqListDerstory(&s1);
}

int main()
{
	//TestSeqList1();
	//TestSeqList2();
	TestSeqList3();
	
	return 0;
}

2.相关练习

(1)有一个数组和一个值,原地移除所有数值等于这个数的元素,并返回移除后新数组的长度

#include<stdio.h>

//给定数组nums和一个值val 


//思路1:找到所有的val,一次挪动数据覆盖删除
//       时间复杂度O(N*2)  最坏的情况:数组中大部分值甚至全部都是val 
//                                       (n-1)+(n-2)+(n-3)+…… 


//思路2:一次遍历nums数组,把不是val的值,放到tmp数组,再把tmp数组的值拷贝回去
//       时间复杂度O(N)  空间复杂度O(N) 空间换时间


//思路3: src去找nums数组中不等于val的值,放到dst指向的位置上去,再++src,++dst
//双指针 


int removeElement(int* nums,int numsSize,int val)
{
	int src = 0;
	int dst = 0;
	while(src<numsSize)
	{
		if(nums[src]!=val)
		{
			nums[dst]=nums[src];
			++src;
			++dst;
		}
		else
		{
			++src;
		}
	}
	return dst;
 } 
 
int main()
{
	int nums[5]={1,3,4,3,5};
	int val=3;
	printf("%d\n",removeElement(nums,5,val));
	return 0;
}
	

(2)原地删除重复元素,使每个元素只出现一次,返回删除后数组长度

//去重
#include<stdio.h>

int removeDuplicates(int* nums,int numsSize)
{
	if(numsSize==0)
	{
		return 0;
	}
	
	int i = 0;
	int j = 1;
	int dst = 0;
	while(j<numsSize)
	{
		if(nums[i]==nums[j])
		{
			++j;
		}
		else
		{
			nums[dst]=nums[i];
			++dst;
			i = j;
			++j;
		}
	}
	
	nums[dst]=nums[i];
	++dst;
	return dst;
}


int main()
{
	int nums[]={0,0,1,1,1,2,2,3,3,4};
	
	printf("%d\n",removeDuplicates(nums,10));
	
	return 0;
} 

3.顺序表优缺点

顺序表缺陷:

  1. 空间不够需要增容,增容需要代价

增容分为:①原地扩

          ②异地扩

  1. 避免频繁扩容,我们满了基本都是扩二倍,可能就会导致一定的空间浪费。
  2. 顺序表要求数据从开始位置连续存储,那么我们在头部或者中间位置插入或删除数据就需要挪动数据,效率不高。
  3. 针对顺序表缺陷,设计出链表。

优点:

支持随机访问

有些算法,需要结构支持随机访问,比如二分查找、优化的快排等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值