【数据结构与算法】顺序表精讲

所属专栏:数据结构与算法

前期内容:

  1. 绪论1——抽象数据类型
  2. 绪论2——时间复杂度与空间复杂度
  3. 与时间复杂度相关的OJ面试题
  4. 抽象数据类型的实现

目录

1.1线性表的定义和特点

1.2案例引入

eg: 图书信息管理系统:

1.3线性表的类型定义

基本操作

1.4顺序表的顺序表示

顺序表的顺序表示

顺序表的特点

顺序表的实现

        概念及结构

代码实现


1.1线性表的定义和特点

        例如:

  •  12星座(双鱼、白羊、水瓶….)
    • 某单位历年拥有的计算机的数量(100、120…)
    • 26个英文字母(A,B,C,…,Z)

这些都是线性表。表中的每一项就是一个数据元素。在稍微复杂的线性表中,一个数据元素可以包含若干个数据项。

同一线性表中的元素必定具有相同特性,数据元素间的关系是线性关系。

对千非空的线性表或线性结构, 其特点是:

(1) 存在唯一的一个被称作 “第一个" 的数据元素;

(2)存在唯一的一个被称作 “最后一个" 的数据元素;

(3)除第一个之外, 结构中的每个数据元素均只有一个前驱;

(4)除最后一个之外,结构中的每个数据元素均只有一个后继。

 线性表是n个具有相同特性的数据元素的有限序列。线性表是一种实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就是说是连续的一条直线,但在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

1.2案例引入

eg: 图书信息管理系统:

需要的功能:查找、插入、删除、修改、排序、计数

图书表抽象为线性表

表中每本图书抽象线性表中的数据元素

可以使用:图书顺序表、图书链表

  • 选择适当的存储结构
  • 实现此存储结构上的基本操作
  • 利用基本操作完成功能

1.3线性表的类型定义

抽象数据类型线性表的定义如下:

ADT List{

数据对象:D={ai|ai属于Elemset,(i=1,2…,n,n>=0)}

数据关系:R={|ai-1,ai属于D,(i=2,3,…,n)}

基本操作:

initList(&L);

DestroyList(&L);

….

等等

}ADT List

基本操作

  • InitList(&L)

操作结果:构造一个空的线性表L

  • DestroyList(&L)

初始条件:线性表L已经存在

操作结果:销毁线性表L

  • CharList(&L)

初始条件:线性表L已经存在

操作结果:将线性表L重置为空表

  • ListEmpty(L)

初始条件:线性表L已经存在

操作结果:若线性表为空表,则返回ture;否则返回false

  • ListLength(L)

初始条件:线性表L已经存在

操作结果:返回线性表L中的数据元素个数

  • GetElem(L,i,&e)

初始条件:线性表L已经存在,1<=i<=Listlength(L)

操作结果:用e返回线性表L中第i个数据元素的

  • LocateElem(L,e,compare())

初始条件:线性表L已经存在,compare()时数据元素判定函数

操作结果:返回L中第一个与e满足compare()的数据元素的位序,若这样的元素不存在则返回0;

  • PriorElem(L,cur_e,&pre_e)

初始条件:线性表L已经存在

操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败;pre_e无意义

  • NextElem(L,cur_e,&next_e)

初始条件:线性表L已经存在

操作结果:若cur_e是L的是元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,则next_e无意义。

  • LinstInsert(&L,i,e)

初始条件:线性表L已经存在,1<=i<=ListLength(L)+1

操作结果:在L的第i个位置之前插入新的数据元素e,L的长度加1.

  • ListDelete(&L,i,&e)

初始条件:线性表L已经存在,1<=i<=ListLength(L)

操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减一

删除前(长度为n):(a1,a2…,ai-1,ai,ai+1,…an)

删除后(长度为n-1):(a1,a2,…ai-1,ai+1,…,an)

  • ListTraverse(&L,visited())

初始条件:线性表L已经存在

操作结果:依次对线性表中每个元素调用visited()

以上所提及的运算时逻辑结构上定义的运算。只是给出了这些运算的功能是“做什么”,至于“如何做”等实现细节,只有待确定了存储结构之后才考虑。

1.4顺序表的顺序表示

顺序表的顺序表示

       线性表的顺序表示又称为顺序存储结构或顺序映像

【数据结构与算法】顺序表精讲_第1张图片

 线性表的第一个数据元素a1的存储位置,称作线性表的起始位置或基地址

【数据结构与算法】顺序表精讲_第2张图片

 如果每个元素占用8个存储单元,ai存储位置是2000单元,则ai+1存储位置是?2008

由于线性表顺序存储结构占用一片连续的存储空间。因此知道某个元素的存储位置就可以计算其他元素的存储位置。

顺序表的特点

        以物理位置相邻表示逻辑关系,任一元素均可随机存取

顺序表的实现

        概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表一般可以分为:

  1. 静态顺序表:使用长数组存储。
  2. 动态顺序表:使用动态开辟的数组存储。

顺序表的静态存储

//顺序表的静态存储
#define N 7        //定义一个宏,大小为7
typedef int SQDataType;        //自定义数据类型为int型

typedef struct SeqList
{
SQDataType array[N];    //定义数组
size_t size;            //定义数据的实际个数
}seqList;

顺序表的动态存储

//顺序表的动态存储
typedef struct SeqList
{
    SLDataType* array;    //指向动态开辟的数组
    size_t size;         //有效数据个数
    size_t capicity;    //容量空间的大小
}SeqList;

补充:C语言的内存分配函数

需加载头文件

  • malloc(m)函数:开辟m字节长度的地址空间,并返回这段空间的首地址
  • sizeof(x): 计算变量x的长度
  • free(p)函数:释放指针p所指变量的存储空间,即彻底删除一个变量

代码实现

#include 
#include "malloc.h"	//用到malloc函数:为结构体开辟一段内存空间
#include "assert.h"		//顺序表初始化时,用来检测通过malloc开辟的内存空间是否为空

#define maxsize 8	//该顺序表最多可容纳的长度为8


typedef int Elemtype; 
typedef struct SeqList
{
	Elemtype *base;		//顺序表的首地址 
	int capacity;		//顺序表的总容量 
	int size;			//顺序表的实际大小 
};

//函数声明

 void initSeqList(SeqList *list);					//初始化顺序表 ,构造一个空的线性表 
 void push_back(SeqList *list,Elemtype val);		//尾插:val代表要插入的数据
 void push_front(SeqList *list,Elemtype val);		//头插,val代表要插入的数据
 void delete_back(SeqList *list);					//尾删
 void delete_front(SeqList *list);					//头删
 void show_list(SeqList *list);						//5.遍历输出顺序表
 void insert_pos(SeqList *list,int pos,Elemtype val);//6.按位置插入数据,val代表要插入的数据,pos代表位置
 void delete_pos(SeqList *list,int pos);			//7.按位置删除元素
 int listlength(SeqList *list);						//8.求顺序表长度
 int find(SeqList *list,Elemtype val);			//9.寻找数据,val代表要寻找的数据
 void delete_val(SeqList *list,Elemtype val);		//10.按值删除元素,val为需要删除的元素
 void sort(SeqList *list);							//排序
 void inverse(SeqList *list);						//12.倒置
 void clearlist(SeqList *list);						//13.清除顺序表
 void destroylist(SeqList *list);					//14.销毁顺序表
 
 //函数实现
 
 //初始化顺序表
 void initSeqList(SeqList *list) 
 {
 	list->base= (Elemtype*)malloc(maxsize*sizeof (Elemtype));//动态分配内存 
 	if(list->base != NULL)
 		list->capacity = maxsize;		//总容量为顺序表初始大小 
 		list->size = 0;					//将顺序表实际大小置为0 
 }
 
//1.尾插
void push_back(SeqList *list,Elemtype val) 
{
	if(list->size == list->capacity)
	{
		printf("该顺序表已满,不能再插入元素\n");
		return;//该语句的作用:使程序不再往下进行,提高程序的效率 
	}
	else {
		list->base[list->size]=val;
		list->size++;
	}
}
 
 //2.头插 
 void push_front(SeqList *list,Elemtype val)
 {
 	if(list->size >= list->capacity)
	{
		printf("该顺序表已满,不能再插入元素\n");
		return;
	}
	else
	{
		for(int i= list->size; i>0; i--)
		{
			list->base[i] = list->base [i-1];
		}
		list->base [0] = val;
		list->size ++; 
	 } 
 }
  //3.尾删
  void delete_back(SeqList *list) 
  {
  	if(list->size==0)
  	{
  		printf("顺序表为空,不能删除元素\n");
	  }
	  else
	  {
	  	list->size --;		
	  }
  }
 
 //4.头删
  void delete_front(SeqList *list)
  {
  	if(list->size == 0)
  	{
		printf("顺序表为空,不能删除元素\n");
  		return;
   }
  	for(int i= 0;isize -1 ;i++)
  	{
		list->base [i]=list->base [i+1];
	 }
		list->size --;
	 
  }
 
 //5.遍历输出顺序表 
 void show_list(SeqList *list)
 {
 	for(int i =0;isize ; i++)
 		printf("%d",list->base [i]);
 	printf("\n");
 }
 
 //6.按位置插入元素
   void insert_pos(SeqList *list,int pos,Elemtype val)
   {
   	if(list->size == list->capacity )
   	{
   		printf("位置已满,不能插入元素");
   		return;
	   }
	if(pos<1||pos>list->size +1)
	{
		printf("插入的位置不正确,不能插入元素");
		return;
	}
	else
	{
		for(int i=list->size ;i>=pos;i--)
		{
			list->base [i]=list->base [i-1];
		}
		list->base [pos-1]= val;
		list->size ++; 
	}
   }
  
  //7.按位置删除元素
  void delete_pos(SeqList *list,int pos)
  {
  	if(list->size == 0){
  		printf("顺序表为空,无法删除元素");
  		return;
	  }
  	if(pos<1 ||  pos>list->size)
	{
		printf("位置不正确,无法删除元素");
		return;
	}
	for(int i= list->size+1 ;i>=pos+2;i--){
		
			list->base [i]=list->base [i+1]; 
		}
		list->size --; 
	
   } 
   
   //8.求顺序表长度
   int listlength(SeqList *list)
   {
   		return list->size ;
	} 
	
//9.查找元素
int find(SeqList *list,Elemtype val)
{
	for(int i=0; isize ; i++)
	{
		if(list->base [i]==val)
			return i+1;
	 } 
	 return -1;
}

//10. 按值删除元素 
void delete_val(SeqList *list,Elemtype val)
{
	if(list->size ==0){
		printf("该顺序表为空,无法按值删除元素");
		return;
	}	
	if (find(list, val) == -1)
	{
		printf("要删除的数据%d不存在该顺序表中!\n",val);
		return;
	}
	else
		delete_pos(list, find(list, val));
}
 
 //11.排序(冒泡排序) 
 void sort(SeqList *list)
 {
 	if(list->size == 0){
 		printf("该顺序表为空,无法排序");
 		return;
	 }
	 for (int i = 0; i < list->size-1; i++)  //冒泡法 
	{
		for (int j = 0; j < list->size-1-i; j++)
		{
			if (list->base[j] > list->base[j+1])
			{
				Elemtype temp = list->base[j];
				list->base[j] = list->base[j+1];
				list->base[j+1] = temp;
			}
		}
	}
  } 
  
  //12.倒置
  void inverse(SeqList *list)
 {
  
  	if(list->size ==0)
  	{
		printf("顺序表为空,无法倒置");
  		return ;
  	}
  	if(list->size == 1)
  	{
		printf("顺序表长度为1,无法倒置");
	 	return ;
	}
	for(int i=0;isize / 2;i++)
	{
		Elemtype temp;//中间量
		temp = list->base [i];
		list->base [i] = list->base [list->size -i-1]; 
		list->base [list->size -i-1] = temp;
	}
  }
   
   //13.清除顺序表 
   void clearlist(SeqList *list)
   {
   	list->size = 0;
   	printf("顺序表已清楚");
   }
   
   //14. 销毁顺序表 
   void destroylist(SeqList *list)
   {
   	free(list->base);		
	list->base == NULL;
	list->capacity = 0;
	list->size = 0;
   }
   
   //主函数
   
 int main()
{
   	SeqList mylist;//创建一个结构体变量;
	initSeqList (&mylist);//初始化顺序表
	
	push_back(&mylist, 1);     //插入数据 
    push_back(&mylist, 2);
    push_back(&mylist, 3);
    push_front(&mylist, 5);
    push_back(&mylist, 4);
    push_front(&mylist, 6);
    
	int select=1;
	int pos;//代表要插入的位置
	Elemtype  item;//代表要插入的的位置
	

		printf("\n----------------------------------------------------------------\n");
		printf("-	[1]尾插	                    [2]头插                    -\n");
		printf("-	[3]尾删                     [4]头删                    -\n"); 
		printf("-	[5]遍历输出顺序表           [6]按位置插入元素          -\n"); 
		printf("-	[7]按位置删除元素           [8]求顺序表长              -\n"); 
		printf("-	[9]查找元素                 [10]按值删除元素           -\n"); 
		printf("-	[11]排序                    [12]倒置                   -\n");
		printf("-	[13]清除顺序表              [14]销毁顺序表             -\n"); 
		printf("\n----------------------------------------------------------------\n");
		
		
	while(select)
	{
		printf("请输入你的选择:");
		scanf("%d",&select); 
		
		if(select==0)
			break;
			
		switch(select)
		{
			case 1:
				printf("请输入结尾要插入的元素:");
				scanf("%d",&item); 
				push_back(&mylist, item);
				break;
				
			case 2:
				printf("请输入头部要插入的元素:");
				scanf("%d",&item);
				push_front(&mylist,item);
				break;
				
			case 3:
				printf("尾删:\n");
				delete_back(&mylist);
				break;
				
			case 4:
			    printf("头删:\n");
				delete_front(&mylist);
				break;
				
			case 5:
			    printf("遍历输出顺序表:\n");
				show_list(&mylist);
				break;
				
			case 6:
				printf("请输入要插入的位置:");
				scanf("%d",&pos);
				printf("请输入要插入的元素:");
				scanf("%d",&item);
				insert_pos(&mylist,pos,item);
				break;
				
			case 7:
				printf("请输入要删除的位置:");
				delete_pos(&mylist,pos);
				break;
				
			case 8:
				printf("该顺序表的长度为:%d",listlength(&mylist));
				break;
			
			case 9:
				printf("请输入需要查找的元素:");
				pos = find(&mylist,item);
				if (pos == -1)
					printf("要查找的数据%d在顺序表中不存在!",item);
				else
					printf("要查找的数据%d在顺序表中的位置是: %d",item,pos);				
				break;
				
			case 10:
				printf("请输入要删除的元素:");
				scanf("%d",&item);
				delete_val(&mylist,item);
				break;
			
			case 11:
				printf("排序:");
				sort(&mylist);
				break;
					
			case 12:
				printf("倒置:");
				inverse(&mylist);
				break;
				
			case 13:
				printf("清除顺序表:\n");
				clearlist(&mylist);
				break;
				
			case 14:
				printf("顺序表已销毁\n");
				destroylist(&mylist);
				break;
				
			default:
				printf("输入的信息有误,请重新输入");
				break; 
		}
	 } 
	destroylist(&mylist);///*销毁顺序表的方法,写在while循环外面,写在main函数将要结束时,释放掉malloc开辟的空间*/
}

 今天的内容到这里就结束啦~

下期预告:顺序表相关的OJ面试题

你可能感兴趣的:(数据结构与算法(C语言版),数据结构,c语言,算法)