CDay06(数据结构)用动态数组来实现栈和队列(动态内存分配,动态数组,栈,队列,时间复杂度,空间复杂度)

目录

 

0x00动态内存分配一般用在什么地方?

0x01动态内存分配实现动态的数据结构

如何实现动态数组?

栈:特殊的动态数组,只能够先入后出,后入先出。

0x02作业:写一个队列


0x00动态内存分配一般用在什么地方?

数组必须规定大小,一定得等到程序结束,才能释放内存。

为了防止内存浪费,我们一般都要使用动态内存分配。动态内存分配能够及时的把开出的内存释放掉,而不是等到程序结束才去释放。因为一般的大型程序都是7x24小时运行的,如果我们总是使用数组,就会导致我们的程序开了很多内存都没有释放,这样可能导致内存不够用。如果不使用动态内存分配,那么即便你内存有几个T,大型程序也会开完的,开完之后,你只能重启程序了,但是有很多程序,例如淘宝的服务器开了就不能停的。所以一定要学会用动态内存分配来节约内存。

注意:除非程序结束或者手动释放,否则new和malloc开的内存一直被占用。

0x01动态内存分配实现动态的数据结构

动态数组:数组大小是变化的。

如何实现动态数组?

由一个指针变量+一个记录数组元素个数的变量来实现动态数组。

有了动态数组之后,我们就可以用动态数组来实现队列和栈了。

栈:特殊的动态数组,只能够先入后出,后入先出。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//实现动态的数组,我们只需要先用4字节开一个指向int类型的指针,先让它指向空,然后开内存段,让指针指向内存段 
int* p=NULL;
//记录数组中元素的个数 
int len =0;
//增加一个元素 
void add(int data); 
//删除 
void pop();
//遍历 
void travel();
//获取栈顶元素
int  getTop(); 
int main(int argc, char *argv[]) {
	add(1);
	add(2);
	add(3);
	pop();
    travel();

	return 0;
}
void pop(){
	if(len==1){
	   free(p);
	   p=NULL;
	   len--;
	} 
	else if(len>1){
		int* pNew=(int*)malloc((len-1)*sizeof(int));
		memcpy(pNew,p,(len-1)*sizeof(int));
		free(p); 
		p=pNew;
		len--;
	}
	return;
}
int  getTop(){
	if(len){
		return p[len-1];
	}
	return -1;

}
void add(int data){
  //如果本来没有数据
   int* pNew;
   if(p==NULL){
   	//需要先开一个内存段,然后将数据放到该内存段里面去 
   	pNew=(int*)malloc((len+1)*sizeof(int));//开内存段,然后将返回的指针强制转化为int*类型
 
}
  else
  //如果本来有数据 
   {
	pNew=(int*)malloc((len+1)*sizeof(int));
	//拷贝原有数据
	memcpy(pNew,p,len*sizeof(int));//(目的地首地址,原有内存首地址,拷贝多少字节) 
	//释放原有内存
	free(p); //注意这个代表释放p指向的内存段,而不是释放p的所占据的内存 
	 
    }  
    pNew[len++]=data;
	p=pNew; //p指向新开内存
}
void travel(){
		int i;
		for(i=0;i<len;i++){
		printf("%d \n",p[i]);
	}
	
}

用动态内存分配实现的动态数组不会浪费任何内存,如果数组里面没有存数据,就不会占用任何内存,数组里面存了多少数据就开多少内存。而普通的数组可能开辟很大内存,却没有存多少数据。

栈:先入后出,后入先出;可以理解为箱子。

队列:先入先出,后入后出;可以理解为日常生活中的排队。

空间复杂度:程序占用内存的多少

时间复杂度:程序运行时间长短。CPU运算次数的多少

用栈实现的动态数组,空间复杂度很低,但是比较耗费CPU,因为每一次放数据进去都要新开内存,还要拷贝。

除了考虑时间复杂度和空间复杂度,我们使用数据结构就是为了增删改查,那么用这种数据结构,我们增删改查容易吗?

0x02作业:写一个队列

注意:内存段释放了,内存段依然存在,占据内存,只是这个程序绑定了这一块内存段,其他程序不能访问该内存段,而释放内存段,是指解除绑定,其他程序也可以访问这块内存段了。不论什么数据结构,它的本质都是对内存段的占用。栈和队列都是用连续内存段来制作的,所以我们可以用一个指针变量来描述一个栈和一个队列。我们只需要知道元素个数和首地址,我们就知道这个队列或者栈了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int* p=NULL;
//记录数组中元素的个数 
int len =0;
//增加一个元素 
void add(int data); 
//删除 
void reduce();
//遍历 
void travel();
int main(int argc, char *argv[]){
	add(1);
	add(2);
	add(3);
	add(4);
	add(8);
	reduce();
	reduce();
    travel();

	return 0;
}
void reduce(){
	if(len==1){
	   free(p);
	   p=NULL;
	   len--;
	} 
	else if(len>1){
		int* pNew=(int*)malloc((len-1)*sizeof(int));
		memcpy(pNew,p+1,(len-1)*sizeof(int));
		free(p); 
		p=pNew;
		len--;
	}
	return;
}

void add(int data){
  //如果本来没有数据
   int* pNew;
   if(p==NULL){
   	//需要先开一个内存段,然后将数据放到该内存段里面去 
   	pNew=(int*)malloc((len+1)*sizeof(int));//开内存段,然后将返回的指针强制转化为int*类型
 
}
  else
  //如果本来有数据 
   {
	pNew=(int*)malloc((len+1)*sizeof(int));
	//拷贝原有数据
	memcpy(pNew,p,len*sizeof(int));//(目的地首地址,原有内存首地址,拷贝多少字节) 
	//释放原有内存
	free(p); //注意这个代表释放p指向的内存段,而不是释放p的所占据的内存 
	 
    }  
    pNew[len++]=data;
	p=pNew; //p指向新开内存
}
void travel(){
		int i;
		for(i=0;i<len;i++){
		printf("%d \n",p[i]);
	}
	
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*************************************************************** 
使用动态内存分配的前提,这个程序是7*24小时连续不断运行的。     * 
如果这个程序不是7*24小时连续不断运行的,我们不需要动态内存分配 * 
****************************************************************/
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//队列 
//初始化队列
void initQueue(int** queue,int* pLen);//int** queque表示指向“指向int类型的指针”的指针  
//入队
void pushQueue(int** queue,int* pLen,int data); 
//遍历函数
void travel(int** queue,int* pLen); 
//获得队首元素
int getHead(int*queue); 
//返回队尾元素 
int getTail(int*queue,int Len);
//修改某个元素值
void setOneOfQueue(int** queue,int idx,int len,int data); 
//出队
void pop(int** queue,int* pLen){
	if(*queue){//队伍非空才出队
	   if(*pLen == 1){
	   	 free(*queue);
		 *queue=NULL;
		 *pLen=0; //容易忘记 
		 return;
	   	}
	   int* pNew=(int*)malloc(sizeof(int)*((*pLen)-1));
	   memcpy(pNew,(*queue)+1,sizeof(int)*((*pLen)-1));
	   free(*queue);
	   *queue=pNew;
	   (*pLen)--;
	   return;
	}
} 

int main(int argc, char *argv[]){
	int* pBuff;
	int len;
	printf("pBuff:%d,len:%d",pBuff,len);
	initQueue(&pBuff,&len);//因为只有模拟按引用传参,才能通过函数修改pbuff和len;否则修改的只是副本 
	printf("pBuff:%d,len:%d",pBuff,len);
	printf("\n");
	pushQueue(&pBuff,&len,0);
	pushQueue(&pBuff,&len,1);
	pushQueue(&pBuff,&len,2);
	pushQueue(&pBuff,&len,3);
	pushQueue(&pBuff,&len,4);
	pushQueue(&pBuff,&len,5);
	travel(&pBuff,&len);
	setOneOfQueue(&pBuff,1,len,1111);
	travel(&pBuff,&len);
	//void pop(int** queue,int* pLen)
	pop(&pBuff,&len);
	travel(&pBuff,&len);
	printf("head:%d,tail:%d\n",getHead(pBuff),getTail(pBuff,len));
	
	
 return 0;
}
void initQueue(int** queue,int* pLen){
	*queue=NULL;
	*pLen=0;
}
//入队函数 
void pushQueue(int** queue,int* pLen,int data){
	//新开内存
	int* pNew=(int*)malloc(sizeof(int)*(*pLen+1));
	//判断原来是否有数据
	if(*queue){//有数据,拷贝原有数据 
	memcpy(pNew,*queue,sizeof(int)*(*pLen+1));
	free(*queue);
	pNew[(*pLen)++]=data;
	*queue=pNew;
	} 
	else{//没有数据
      pNew[(*pLen)++]=data;
	  *queue=pNew;	
	} 
}
//遍历函数 
void travel(int** queue,int* pLen){
	int i;
	for(i=0;i<(*pLen);i++){
		printf("%d\n",(*queue)[i]);
	} 
}
//获得队首元素
int getHead(int*queue){
	if(queue) return queue[0];
	return -1;
}
//返回队尾元素 
int getTail(int*queue,int Len){
	if(queue) return queue[Len-1];
	return -1;
}
//修改某个元素值 
void setOneOfQueue(int** queue,int idx,int len,int data){
	if(!(*queue)) return;//队伍为空 
	if(idx<0 || idx>(len-1)) return;//下标不对
	(*queue)[idx]=data; 
	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值