大话数据结构与算法(三)

大话数据结构与算法-程杰

第三章 线性表

线性表的定义
       零个或多个数据元素的有限序列。
这里需要强调几个关键的地方:

  1. 首先该线性表一定是有序的,若元素有多个,则第一个元素无前驱,最后一个元素无后继,其他元素都有且只有一个前驱和后继;
  2. 其次,线性表强调有限,也就是元素必须是有限的。
    用数学语言来进行定义。可如下:
           若将线性表记为(a1, …, ai-1, ai, ai+1, …, an),则表中ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素。当i=1, 2, …, n-1时,ai有且仅有一个直接后继,当i=2, 3, …, n时,ai有且仅有一个直接前驱。如下所示:
    在这里插入图片描述
           所以线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,称为空表
           在非空表中的每个数据元素都以一个确定的位置,如a1是第一个数据元素,是最后一个数据元素,ai是第i个数据元素,称i为数据元素ai在线性表中的位序。

线性表的顺序存储结构

  1. 顺序存储结构的定义
           线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素
  2. 顺序存储方式
           线性表的顺序存储结构,说白了,就是在内存中找了块地儿,通过占位的形式,把一块内存给占了,然后把相同数据类型的数据元素依次存放在这块空地上。既然线性表的每个数据元素的类型都相同,所以可以通过一维数组来实现顺序存储结构,即把第一个数据元素存到数组下标为0的位置中,接着把线性表相邻的元素存储在数组中相邻的位置。
           在建立顺序表时,除了预先申请内存空间,还需要实时记录顺序表的长度和顺序表本身申请的内存大小,便于后期对顺序表中的数据元素进行调取。所以,顺序存储的结构代码为:
     #define MAXSIZE 20	 // 存储空间出事分配量
     typedef int ElmType;	// ElmType类型根据实际情况而定,这里假设为int
     typedef struct
     {
	     ElmType data[MAXSIZE];		// 数据存储数据元素,最大值为MAXSIZE
	     int length;				// 线性表当前长度
     }SqList;

       这里,我们发现描述顺序存储结构需要的三个属性:
       <1> 存储空间的起始位置:数据data,它的存储位置就是存储空间的存储位置;
       <2> 线性表的最大存储容量:数组长度MAXSIZE;
       <3> 线性表的当前长度:length
3. 数据长度与线性表长度区别
       数组的长度是存放线性表的存储空间的长度,存储分配后这个量一般是不变的。有个别人可能会问,数组的大小一定不可以变吗?我怎么看有些书中谈到可以动态分配的一维数组。是的,一般高级语言,比如C、C++、VB都可以用编程手段实现分配数组,不过会带来性能上的损耗。
       线性表的长度是线性表中数据元素的个数,随着线性表插入和删除操作的进行,这个量是改变的。
       任意时刻,线性表的长度应该小于等于数组的长度
4. 顺序存储结构的基本操作
ADT 线性表(List)
Data
       线性表的数据对象集合为{a1, a2, …, an},每个元素的类型为DataType。其中,除第一个元素a1外,每一个元素有且只有一个前驱元素,除了最后一个元素an外,每一个元素有且只有一个直接后继元素。数据元素之间的关系是一对一的关系。
Operation

int InitList (SqList *L);	/** 初始化一个顺序表 **/
bool ListEmpty (L);	/** 若线性表为空,返回true,否则返回false **/
int printList (SqList L);	/** 打印线性表中的每一个元素 **/
int getlength (SqList L);	/** 返回线性表元素的个数 **/

/** 创建一个链表长度为length的线性表 **/
int createList (SqList *L,int length);	

/** 在线性表的第pos个位置插入 一个新元素elem **/
int insertList (SqList *L, int pos,ElemType elem);	

/** 将线性表中第pos个位置的元素返回,保存在*e中 **/
int getElem (SqList L, int pos, ElemType *e);	

/** 在线性表中查找与给定元素e相等的元素,如果有相同的返回状态值1,
如果没有,返回状态值0 **/
int locateElem (SqList L, ElemType e);	

/** 从线性表中删除pos位置处的元素,并将其存放在elem中; **/
int deleteList (SqList *L, int pos,ElemType *elem);	

int clearList (SqList L,SqList *pL);	/** 清空顺序表 **/

<一> 初始化一个顺序表

int initList (SqList *L)
{
   L->length=0;
   return 1;
}

<二> 判断线性表是否为空

bool ListEmpty (L)
{
	if (L.length == 0)
		return false;
	return true;
}

<三> 打印线性表中的每一个元素

int printList (SqList L)
{
	// 线性表是否为空
     if (L.length==0)
    	return 0;
    
     for (int i=0; i<L.length; i++)
	 {
          printf("data[%d] = %d\n",i,L.data[i]);
      }
      return 1;
}

<四> 返回线性表元素的个数

int getlength (SqList L)
{
    return L.length;
}

<五> 创建一个链表长度为length的线性表

int createList (SqList *L,int length)
{
    srand(time(0));
    int i;
    for (i=0;i<length;i++)
    {
        L->data[i]=rand()%100;// 插入随机数
        L->length++;
    }
    return 1;
}

<六> 指定位置pos处插入一个新的元素elem
插入算法思路:
A. 如果插入元素不合理,抛出异常;
B. 如果线性表长度大于数组长度,则抛出异常或动态增加容量;
C. 从最后一个元素开始遍历到第i个位置,分别将它们都向后移动一个位置;
D. 将要插入元素填入第i个位置;
E. 表长度加1。

int insertList (SqList *L, int i,ElemType elem)
{
	if (L->length == MAXSIZE)	// 顺序表已满
		return 0;
    if (pos<1 || pos>L->length) // 当pos不在范围内
    	return 0;    
    if (pos<L->length)
    {
		for (int i=L->length-1;i>=pos-1;i--)
    	{// 将要插入位置后数据往后移动一个位置
        	L->data[i+1]=L->data[i];
    	}
	}
    
    L->data[pos-1] = elem; // 将新元素插入 
    L->length++;
    return 1;
}

<七> 获取顺序表中指定位置处的元素值

int getElem (SqList L, int pos, ElemType *e)
{
    if (pos<1 || pos>L.length)
    	return 0;
    	
    *e = L.data[pos-1];
    return 1;
}

<八> 查找在线性表中是否含有指定元素

int locateElem (SqList L, ElemType e)
{
    for (int i=0;i<L.length;i++)
    {
        if (L.data[i] == e)
        {
            printf("在pos[%d]位置处,查找到了元素elem:%d\n",i+1,e);
            return 1;
        }
    }
    return 0;
}

<九> 删除顺序表中指定位置处的元素
删除算法的思路:
A. 如果删除位置不合理,抛出异常;
B. 取出要删除的元素;
C. 从删除元素位置开始遍历到最后一个元素,分别将它们都向前移动一个位置;
D. 表长度减去1.

int deleteList (SqList *L, int pos,ElemType *elem)
{
	if (L->length == 0)	 //线性表为空
		return 0;
    if (pos<1 || pos>L->length)		// 删除位置不合理
   		return 0;
   		
    *elem = L->data[pos-1];
    if (pos<L->length)	// 如果删除不是最后位置
    {
		for (int i=pos;i<L->length;i++)
		{
        	L->data[i-1]=L->data[i];  // 将删除位置后继元素前移
    	}
	}
    
    L->length --;
    return 1;
}

<十> 清空一个顺序表,将顺序表的length置为0

int clearList (SqList L,SqList *pL)
{
    L.length=0;
    pL->length=0;
    return 1;
}
  1. 线性表顺序存储结构的优缺点
           顺序表是用一段地址连续的存储单元依次存储线性表的数据元素。其特点是:内存中地址连续,支持随机查找,按位查找算法的时间复杂度为O(1),按值查找的平均时间性能是O(n),插入删除操作的平均时间性能是O(n),适用于需要大量访问元素,而没有或少量增添或删除元素的程序。

        顺序表的优点为:随机访问较快,创建简单
        缺点为:插入和删除需要移动大量的元素;表的容量难以确定;造成存储空间的“碎片”等

猜你喜欢

转载自blog.csdn.net/QIJINGBO123/article/details/86543092