您的位置:首页 > 理论基础 > 数据结构算法

数据结构:数组的操作(C语言描述)

2014-02-28 22:29 507 查看
数据的在计算机的存储方式分为:连续存储【数组】,非连续存储【链表、树、图and so on】;今天讨论的将是数组,包括数组的创建、打印输出,在数组后面追加元素,判断数组是否为空,判断数组是否为满,在数组的指定位置添加元素,在数组的指定位置删除元素,数组元素的倒置和数组元素的排序。对应的函数如下:

void Init_arr(struct Array *pArr,int len);//初始化数组
bool append_arr(struct Array *pArr,int val);//在数组后追加一个元素
bool Insert_arr(struct Array *pArr,int pos,int val);//指定位置插入元素
bool Delete_arr(struct Array *pArr,int pos,int *val);//指定位置删除元素

bool IsFull_arr(struct Array *pArr);//判断数组是否满
bool IsEmpty_arr(struct Array *pArr);//判断数组是否空

void show_arr(struct Array *pArr);//打印数组中的元素
void Inversion_arr(struct Array *pArr);//倒置数组中的元素
void SelectSort_arr(struct Array *pArr);//选择排序
void BubbleSort_arr(struct Array *pArr);//冒泡排序


1.数组的组成元素

我们知道确定一个数组,需要知道数组的首地址(pArr),数组的最大长度(len)以及数组当前元素个数;所以我们要做的第一件事就要新建一个数据类型

struct Array
{
   int *pBase; //定义一个指向数组的指针
   int len;    //数组中能够存放的最大元素个数
   int cnt;    //当前数组中元素的个数
};


此时定义一个名为struct Array 的数据类型,只是定义了数据类型并没有分配内存;

struct Array arr;	//定义一个结构体变量,并分配内存在静态区;(静态区、堆,栈)


定义一个变量时通常的格式:数据类型+变量名·(如:int a,定义一个整型变量a),此时定义了一个名为arr的结构体变量,并此变量分配了内存,指针pBase分配了4个字节,len变量分配了四个字节,cnt变量分配了4个字节;但是此时并没有为pBase指向的数组分配内存。因此,要想对数组进行操作,还必须分配一块内存。可以用sizeof函数来看实际分配了多少内存;

printf("字节数: %d",sizeof(struct Array));


此时的输出是12,说明我们的判断并没有错;并没有为数组分配内存,只为结构体中的数据成员分配了内存。

内存的分配三种方式:

(1)从静态存储区中分配,一般全局变量和static修饰的变量从静态区分配

(2)在栈上创建,局部变量的分配

(3)从堆上分配 ,用malloc函数申请内存时,从堆上进行分配

2.数组的创建

函数的一般注释格式:

/*********************************************************************************

*Function: //函数名称

* Description: //函数功能,性能等的描述

*Calls: //被本函数调用的函数清单

*Called By: //调用本函数的清单

*Input: //输入参数的说明,包括每个参数的作用、取值说明及参数间关系

*Output: //输出参数的说明

*Return: //函数返回值的说明

*Others: //其他说明

**********************************************************************************/

/*********************************************************************************
  *Function: Init_arr;
  *Description: 创建并初始化一个数组;
  *Calls:  malloc()、printf()、exit();
  *Called By:  none
  *Input:  参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
           参数——len是说明创建的数组的容量,也就是能装元素的最大个数;
          //输入参数的说明,包括每个参数的作用、取值说明及参数间关系;
  *Output:  none
  *Return:  none
  *Others:  none
**********************************************************************************/
void Init_arr(struct Array *pArr,int len)
{
	
	pArr->pBase=(int *)malloc(sizeof(int)*pArr->len);
	if(NULL==pArr->pBase)
	{
		printf("分配内存失败");
		exit(-1);   //终止程序
		
	}
	else
	{
	   pArr->cnt=0;
	   pArr->len=len;
	}
		return;  //加return的目的是为了告诉其他人,此函数到此已经写完了
}


pArr->pBase=(int *)malloc(sizeof(int)*pArr->len);
(1)用malloc(参数1)函数分配了一块内存,内存的大小是参数1的大小,并且指针pArr->pBase指向这块内存的首地址。很多人认为这是为指针pArr->pBase分配了内存,这是不对的;对于32的系统,任何指针所在内存的大小都是4个字节,指针就是用来存放地址编号的,但存放指针内存的地址编号,往往我们不需要关心。

(2)用malloc()函数分配内存,若是分配成功,则会把这块内存的首地址赋给指针pArr->pBase;若是分配失败,会把NULL赋给指针;

if(NULL==pArr->pBase)
	{
		printf("分配内存失败");
		exit(-1);   //终止程序
		
	}


因此需要检查,内存分配失败,用函数exit(-1)函数退出程序。

(3)malloc函数的用法

void * malloc(int ); 函数的形参是一个整型数据,用来说明申请内存的大小,单位是字节。malloc函数的返回值是个void类型的指针,因此 往往需要强制转换所需要的类型指针; 例如,

pArr->pBase=(int *)malloc(sizeof(int)*pArr->len);
就是强制转换成指向整型的的指针,(int *)(参数1),就是把参数1强制转换成int * 类型;

3.插入一个元素

/*********************************************************************************
  *Function: Insert_arr;
  *Description: 在数组的第pos个元素前,插入val元素;;
  *Calls:  IsFull_arr();
  *Called By: none;
  *Input:  参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
           参数——pos,表示位置,在数组第pos元素前加入数据val;
		   参数——val,表示要插入的数据;
  *Output:  none
  *Return:  布尔量,1表示插入成功;0,插入失败;
  *Others:  none
**********************************************************************************/
bool Insert_arr(struct Array *pArr,int pos,int val)
{
	int i;
	if(IsFull_arr(pArr))          //为空不能进行插入操作
		return false;
	if(pos<1||pos>pArr->cnt+1)  //插入的位置不能在第一个元素前面,也不可以在最后一个元素后面的后面插入
		return false;
	
	    for(i=pArr->cnt-1;i>=(pos-1);i--)
	        pArr->pBase[i+1]=pArr->pBase[i];
	    pArr->pBase[pos-1]=val;
		pArr->cnt++;
		return true;

}
可以往数组中指定位置插入一个元素,必须满足一定的条件:

(1)数组不能满

(2)插入元素的位置要求:不能再第一个元素之前插入,也不可以在数组现有元素的个数,之后之后插入;比如,数组中有3个元素,可以在第3个元素之前插入,也可以在第3个元素位置后面插入(这是写程序人自己规定的)。



比如,我们要在元素56前面加入21,我们要做的就是把数组56,23,56,12,5依次往后移一位,但是我们必须从元素5开始往后移,这样数据才不会覆盖;需要一个循环来完成,循环变量i的初始值应该5的位置,所以i=cnt-1,循环条件:应该是i移到56的位置,此时i=pos-1;

对于一些操作,我们可以用特殊值来试凑,来循环循环变量的初始值,和循环结束条件;

4.删除一个元素

/*********************************************************************************
  *Function: Delete_arr;
  *Description: 删除数组的第pos个元素
  *Calls:  IsFull_arr();
  *Called By: none;
  *Input:  参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
           参数——pos,数组的第pos个元素将被删除
		   参数——val,返回要删除的数据;
  *Output:  把删除的数据,返回给指针val
  *Return:  布尔量,1表示删除成功;0,删除失败;
  *Others:  none
**********************************************************************************/
bool Delete_arr(struct Array *pArr,int pos,int *val)
{
	int i;
	if(IsEmpty_arr(pArr))
		return false;
	if(pos>pArr->cnt||pos<1)
		return false;
	
	*val=pArr->pBase[pos-1];
    for(i=pos;i<=pArr->cnt-1;i++)
		pArr->pBase[i-1]=pArr->pBase[i];
		pArr->cnt--;
	return true;

}




假设,要数组的第三个元素2,即pos=3;要做的动作就是把56,23,56,12,5依次往前移。循环变量的初始位置为第一个56所在的位置,即i=pos。循环结束条件是i<=cnt-1,此时才把需要移的元素移完。

5.选择排序

/*********************************************************************************
  *Function: SelectSort_arr;
  *Description: 用选择排序算法对数组中元素进行排序
  *Calls:  none;
  *Called By: none;
  *Input:  参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
  *Output:  把删除的数据,返回给指针val;
  *Return:  void
  *Others:  none
**********************************************************************************/
void SelectSort_arr(struct Array *pArr)
{
	int i,j,temp;
	for(i=0;i<pArr->cnt-1;i++)
	{
		for(j=i+1;j<pArr->cnt;j++)
		if(pArr->pBase[i]>pArr->pBase[j])
		{
			temp=pArr->pBase[i];
		    pArr->pBase[i]=pArr->pBase[j];
		    pArr->pBase[j]=temp;
		}
	}
}


直接选择排序的基本思想

  n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:

①初始状态:无序区为R[1..n],有序区为空。

②第1趟排序

 在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。

  ……

③第i趟排序

  第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R[i..n](1≤i≤n-1)。该趟排序从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R[i]交换,使R[1..i]和R[i+1..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。

 这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。

6.冒泡排序

/*********************************************************************************
  *Function: BubbleSort_arr;
  *Description: 利用冒泡排序对数组中的元素进行排序
  *Calls:  IsFull_arr();
  *Called By: none;
  *Input:  参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
  *Output:  none
  *Return: none;
  *Others:  none
**********************************************************************************/
void BubbleSort_arr(struct Array *pArr)
{
	int i,j,temp;
	bool exchange=false;
	for(i=0;i<pArr->cnt-1;i++)
	{
		exchange=false;  //开始前排序标志为false,代表没有交换;
		for(j=pArr->cnt-1;j>i;j--)
		{
			if(pArr->pBase[j]<pArr->pBase[j-1])
			{
				temp=pArr->pBase[j];
		        pArr->pBase[j]=pArr->pBase[j-1];
		        pArr->pBase[j-1]=temp;
				exchange=true;
			}
		}
		if(!exchange)
			return ;   //若一趟排序下来,数据没有交换说明,数据中的数据是有序的,就没有必要在进行循环了;	
	}
}


冒泡排序:排序方法

 将被排序的记录数组R[1..n]垂直排列,每个记录R[i]看作是重量为R[i].key的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R:凡扫描到违反本原则的轻气泡,就使其向上"飘浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。

(1)初始

  R[1..n]为无序区。

(2)第一趟扫描

  从无序区底部向上依次比较相邻的两个气泡的重量,若发现轻者在下、重者在上,则交换二者的位置。即依次比较(R
,R[n-1]),(R[n-1],R[n-2]),…,(R[2],R[1]);对于每对气泡(R[j+1],R[j]),若R[j+1].key<R[j].key,则交换R[j+1]和R[j]的内容。

 第一趟扫描完毕时,"最轻"的气泡就飘浮到该区间的顶部,即关键字最小的记录被放在最高位置R[1]上。

(3)第二趟扫描

  扫描R[2..n]。扫描完毕时,"次轻"的气泡飘浮到R[2]的位置上……

 最后,经过n-1 趟扫描可得到有序区R[1..n]

注意:

  第i趟扫描时,R[1..i-1]和R[i..n]分别为当前的有序区和无序区。扫描仍是从无序区底部向上直至该区顶部。扫描完毕时,该区中最轻气泡飘浮到顶部位置R[i]上,结果是R[1..i]变为新的有序区。

附件:程序源码

#include<stdio.h>
#include<stdlib.h> //包含了exit函数
#include"malloc.h"
//定义一个新的数据类型,并没有分配内存空间
struct Array { int *pBase; //定义一个指向数组的指针 int len; //数组中能够存放的最大元素个数 int cnt; //当前数组中元素的个数 };

void Init_arr(struct Array *pArr,int len);//初始化数组 bool append_arr(struct Array *pArr,int val);//在数组后追加一个元素 bool Insert_arr(struct Array *pArr,int pos,int val);//指定位置插入元素 bool Delete_arr(struct Array *pArr,int pos,int *val);//指定位置删除元素 bool IsFull_arr(struct Array *pArr);//判断数组是否满 bool IsEmpty_arr(struct Array *pArr);//判断数组是否空 void show_arr(struct Array *pArr);//打印数组中的元素 void Inversion_arr(struct Array *pArr);//倒置数组中的元素 void SelectSort_arr(struct Array *pArr);//选择排序 void BubbleSort_arr(struct Array *pArr);//冒泡排序
int main()
{
struct Array arr; //定义一个结构体变量,并分配内存在静态区;(静态区、堆,栈)
printf("字节数: %d",sizeof(struct Array));
//struct Array *pArr; //定义一个结构体指针,并为此指针分配了4字节的内存
//pArr=(struct Array *)malloc(sizeof(struct Array)); //此时只是为pBsae指针,len,cnt变量分配了内存;
//arr.pBase=(int *)malloc(sizeof(int)*arr.len);
Init_arr(&arr,8);
show_arr(&arr);
append_arr(&arr,2);
append_arr(&arr,5);
append_arr(&arr,54);
append_arr(&arr,54);
append_arr(&arr,89);
if(!append_arr(&arr,18))
printf("追加失败\n");

if(!Insert_arr(&arr,3,99))
printf("插入失败\n");

show_arr(&arr);
int DelElement=0;
int *p=&DelElement;
Delete_arr(&arr,2,p);
printf("删除的元素是:%d\n",*p);
show_arr(&arr);

SelectSort_arr(&arr);
printf("选择排序后\n");
show_arr(&arr);

//show_arr(&arr);
/*Inversion_arr(&arr);
printf("倒置后\n");
show_arr(&arr);

BubbleSort_arr(&arr);
printf("冒泡排序后\n");
show_arr(&arr);
*/
return 0;
}
/********************************************************************************* *Function: Init_arr; *Description: 创建并初始化一个数组; *Calls: malloc()、printf()、exit(); *Called By: none *Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的; 参数——len是说明创建的数组的容量,也就是能装元素的最大个数; //输入参数的说明,包括每个参数的作用、取值说明及参数间关系; *Output: none *Return: none *Others: none **********************************************************************************/ void Init_arr(struct Array *pArr,int len) { pArr->pBase=(int *)malloc(sizeof(int)*pArr->len); if(NULL==pArr->pBase) { printf("分配内存失败"); exit(-1); //终止程序 } else { pArr->cnt=0; pArr->len=len; } return; //加return的目的是为了告诉其他人,此函数到此已经写完了 }
/*********************************************************************************
*Function: show_arr;
*Description: 打印出数组中所有元素;
*Calls: printf();
*Called By: none
*Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
*Output: none
*Return: none
*Others: none
**********************************************************************************/
void show_arr(struct Array *pArr)
{
int i;
printf("数组的最大元素个数:%d\n",pArr->len);
printf("数组的当前元素个数:%d\n",pArr->cnt);
for(i=0;i<pArr->cnt;i++) //只要显示数组中有的元素
printf("%d ",pArr->pBase[i]);
printf("\n");
}
/*********************************************************************************
*Function: append_arr;
*Description: 在数组最后一个元素后面添加一个元素;
*Calls: IsFull_arr();
*Called By: none
*Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
参数——val,要添加的数据;
//输入参数的说明,包括每个参数的作用、取值说明及参数间关系;
*Output: none
*Return: 布尔量,1表示追加成功;0,追加失败;
*Others: none
**********************************************************************************/
bool append_arr(struct Array *pArr,int val)
{
if(!IsFull_arr(pArr))
{
pArr->pBase[pArr->cnt++]=val;
return true;
}
else
return false;
}
/*********************************************************************************
*Function: IsFull_arr;
*Description: 判断数组是否满;
*Calls: none;
*Called By: append_arr(),Insert_arr();
*Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
*Output: none
*Return: 布尔量,1表示数组满;0,数组不满;
*Others: none
**********************************************************************************/
bool IsFull_arr(struct Array *pArr) //true 与 false 一般用于返回bool类型的函数
{
if(pArr->cnt==pArr->len)
{
return true;
}
else
return false;
}
/********************************************************************************* *Function: Insert_arr; *Description: 在数组的第pos个元素前,插入val元素;; *Calls: IsFull_arr(); *Called By: none; *Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的; 参数——pos,表示位置,在数组第pos元素前加入数据val; 参数——val,表示要插入的数据; *Output: none *Return: 布尔量,1表示插入成功;0,插入失败; *Others: none **********************************************************************************/ bool Insert_arr(struct Array *pArr,int pos,int val) { int i; if(IsFull_arr(pArr)) //为空不能进行插入操作 return false; if(pos<1||pos>pArr->cnt+1) //插入的位置不能在第一个元素前面,也不可以在最后一个元素后面的后面插入 return false; for(i=pArr->cnt-1;i>=(pos-1);i--) pArr->pBase[i+1]=pArr->pBase[i]; pArr->pBase[pos-1]=val; pArr->cnt++; return true; }
/*********************************************************************************
*Function: IsEmpty_arr;
*Description: 判断数组是否空;
*Calls: none;
*Called By: Delete_arr();
*Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
*Output: none
*Return: 布尔量,1表示数组空;0,数组不空;
*Others: none
**********************************************************************************/
bool IsEmpty_arr(struct Array *pArr)
{
if(0==pArr->cnt)
return true;
else
return false;
}
/********************************************************************************* *Function: Delete_arr; *Description: 删除数组的第pos个元素 *Calls: IsFull_arr(); *Called By: none; *Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的; 参数——pos,数组的第pos个元素将被删除 参数——val,返回要删除的数据; *Output: 把删除的数据,返回给指针val *Return: 布尔量,1表示删除成功;0,删除失败; *Others: none **********************************************************************************/ bool Delete_arr(struct Array *pArr,int pos,int *val) { int i; if(IsEmpty_arr(pArr)) return false; if(pos>pArr->cnt||pos<1) return false; *val=pArr->pBase[pos-1]; for(i=pos;i<=pArr->cnt-1;i++) pArr->pBase[i-1]=pArr->pBase[i]; pArr->cnt--; return true; }
/*********************************************************************************
*Function: Inversion_arr;
*Description: 倒置数组中的元素
*Calls: none;
*Called By: none;
*Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的;
*Output: none
*Return: none
*Others: none
**********************************************************************************/
void Inversion_arr(struct Array *pArr)
{

int i,j,temp;
for(i=0,j=pArr->cnt-1;i<j;i++,j--) //i,j分别指向数组的首尾元素,没移动一次交换一次,直到不满足条件i<j;
{
temp=pArr->pBase[i];
pArr->pBase[i]=pArr->pBase[j];
pArr->pBase[j]=temp;


}
}
/********************************************************************************* *Function: SelectSort_arr; *Description: 用选择排序算法对数组中元素进行排序 *Calls: none; *Called By: none; *Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的; *Output: 把删除的数据,返回给指针val; *Return: void *Others: none **********************************************************************************/ void SelectSort_arr(struct Array *pArr) { int i,j,temp; for(i=0;i<pArr->cnt-1;i++) { for(j=i+1;j<pArr->cnt;j++) if(pArr->pBase[i]>pArr->pBase[j]) { temp=pArr->pBase[i]; pArr->pBase[i]=pArr->pBase[j]; pArr->pBase[j]=temp; } } }
/********************************************************************************* *Function: BubbleSort_arr; *Description: 利用冒泡排序对数组中的元素进行排序 *Calls: IsFull_arr(); *Called By: none; *Input: 参数一pArr是一个结构体指针变量,用来接受结构体变量的地址的; *Output: none *Return: none; *Others: none **********************************************************************************/ void BubbleSort_arr(struct Array *pArr) { int i,j,temp; bool exchange=false; for(i=0;i<pArr->cnt-1;i++) { exchange=false; //开始前排序标志为false,代表没有交换; for(j=pArr->cnt-1;j>i;j--) { if(pArr->pBase[j]<pArr->pBase[j-1]) { temp=pArr->pBase[j]; pArr->pBase[j]=pArr->pBase[j-1]; pArr->pBase[j-1]=temp; exchange=true; } } if(!exchange) return ; //若一趟排序下来,数据没有交换说明,数据中的数据是有序的,就没有必要在进行循环了; } }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: