线性结构:线性表得顺序表示和实现

本文基于严蔚敏《数据结构C语言版》所总结的顺序表笔记

线性结构的特点:

1)存在唯一的第一个数据元素                                                        

2)除第一个元素外,每一个数据元素均只有唯一一个前驱
3)除最后一个数据元素外,每一个数据元素均只有唯一一个后继

线性表中元素的个数n(n>=0)定义为线性表的长度,n=0为空表。非空表中每一个数据元素都有一个确定的位置。

线性表的特点:线性表是一个相当灵活的数据结构,长度可以根据需要增长缩短,即可以根据需求增加长度或缩短长度,可以插入或者删除数据元素。

线性表顺序表示和实现

顺序表示:用一组地址连续的的存储的那元依次存储线性表的数据元素。

线性表顺序表示中第i+1个数据元素的存储位置和第i个数据元素存储位置间隔为每个数据元素所需占用的L个存储单元

由此,确定了初始位置,线性表顺序存储中任意一位数据元素都可以随机存取。

线性表的顺序存储是一种随机存储的存储结构 。


为了方便,下文线性表的顺序存储结构均称为顺序表

线性表动态分配存储结构

为什么要动态分配?不同问题所需长度不同,并且为了防止出现空间不足,要设定动态增加的范围增加程序健壮性 

什么是存储空间基址?该数据得到的内存分配的起始地址

//------------------------顺序表结构体定义---------------------------------
#define LIST_INIT_SIZE 100            //顺序表存储空间的初始分配量
#define LISTINCREMENT 10              //顺序表存储空间的分配增量
//注意,这里没有分号
typedef  struct 
{
	ElemType* elem;    // 存储空间基址
	int length;        // 当前长度
	int listsize;      // 当前分配的存储容量(以sizeof(ElemType)为单位)
} SqList;  // 顺序表

数组指针elem指示顺序表的基地址,length指示顺序表的当前长度 。顺序表的初始化操作就是为顺序表分配一个预定义大小的数组空间,并且将顺序表的当前长度设置为0。listsize指示顺序表当前分配的存储空间大小,一旦因为插入元素而导致空间不足,可再增加一个大小为存储LISTINCREMENT个数据元素的空间.

 构造顺序表

注:因为C语言数组下标从0开始,所以第i个元素是L。elem[i-1]。

// 1.构造一个最大容量为 LIST_INIT_SIZE的空顺序表 
Status InitList(SqList& L) 
{
	    L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
            //用malloc分配一段这么LIST_INIT_SIZE*sizeof(ElemType)多个字节的内存段,它返 
              回一个指向该内存段首字节的指针变量,然后把这个指针变量强制转换为ElemType*类 
              型,再把这个经转换的指针变量赋给L的elem成员,即顺序表的存储空间基址被设定为这么大。
		if (!L.elem)                        //如果内存分配失败
		{
			exit(0);                        //返回错误值0
		}
		    L.length = 0;                   //空表的当前长度设置为0                                                                                    
		    L.listsize = LIST_INIT_SIZE;    //顺序表当前分配的存储空间大小是最大值100

	return 1;                               //构造成功返回1
} // InitList

插入和删除元素

插入:从第i-1个数据元素和第i个数据元素之间插入或删除数据元素

删除:删除第i个数据元素

 注:在第i个元素前插入一个元素,要将从最后一个元素开始直至第i个元素,一个一个向后移动一           个位置。

         删除第i个元素,要从第i+1个元素直至最后一个元素,一个一个向前移动一个位置。

// 3.在顺序表L的第 i 个元素之前插入新的元素e 
Status ListInsert(SqList& L, int i, ElemType e)
{
//传入数据为:线性表的引用,第i个元素,插入数据元素的值
//i的合法值为1<=i<=ListLength+1
			ElemType * newbase, * p, * q;
            //定义新的存储空间基址来防止空间不足
	    if (i<1 || i>L.length + 1)   //如果i值不合法,返回错误值0
           {
            return  0;      
           }                                            
	    if (L.length >= L.listsize)  //如果存储空间满了,增加分配
		    {                                                                                            
		        newbase = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));
 		        if (!newbase)                 //如果内存分配失败,返回错误值0
                   {
                     exit(0);
                   }                                                              
		        L.elem = newbase;             //顺序表存储空间基址变为新的基址                                                                            
		        L.listsize += LISTINCREMENT;  //存储容量大小也跟随增大                                                                
		    }
	            q = &(L.elem[i - 1]);         //q为插入的位置                                                                            
	     for (p = &(L.elem[L.length - 1]); p >= q; --p)  
             {
               *(p + 1) = *p;   //插入位置以及之后的元素右移                                   
	           * q = e;         //插入e                                                                                  
	           ++L.length;      //插入完表长增加1
             }
	           return 1;        //插入结束,返回1
} // ListInsert                         

// 删除顺序表L的第 i 个元素,用e 返回其值 1
Status ListDelete(SqList& L, int i, ElemType& e) 
{
         //传入数据为:引用顺序表L,第i个元素,引用e返回其值
	     ElemType* p, * q;        //指针p指向被删除的元素,q用来移动元素
	     if ((i < 1) || (i > L.length)) //i值不合法返回错误值
            {
             return 0;
            }          
	     p = &(L.elem[i - 1]);     //p为被删除元素的位置
	     e = *p;//被删除元素赋值给p
	     q = L.elem + L.length - 1;//q指向表尾元素的位置
	     for (++p; p <= q; ++p)
             {
		      * (p - 1) = *p;      //被删除元素之后的元素左移
	          --L.length;          //表长-1
             }
	return 1;                      //删除成功返回1
} // ListDelete

 插入和删除算法的时间复杂度是O(n)。

合并算法

什么是非递减排序?意思是关键字递增序排列,但是并非单调递增(因为有重复的关键字)从小到大或者允许中间有相等的情形: 1,2,3,4,5:递增排列, 9,8,7,6,5:递减排列。 1,2,3,3,4,5,8,8:非递减排列, 9,8,7,7,6,5,5,2,1 : 非递增排列。

//----------------------顺序表的合并------------------------------------------
void MergeList(SqList La,SqList Lb,SqList &Lc)
{
//已知顺序表La和Lb的元素按照值非递减排列
//归并La和Lb得到新的顺序表Lc,Lc得元素也按值非递减排列
    ElemType* pa, *pb;
    pa=La.elem;//新的基地址pa
    pb=Lb.elem;//新的基地址pb
    Lc.listsize=Lc.length=La.length+Lb.length;//Lc得长度等于两个长度之和
    pc=Lc.elem=(ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));//新顺序表Lc得基地址
    if(!Lc.elem)
    {
     exit(0);//如果存储分配失败,返回0
    }
   pa_last = la.elem+La.length-1;//找到La得末端
   pb_last = lb.elem+Lb.length-1;//找到Lb得末端
    while(pa<=pa.last&&pb<=pb.last)//归并
    {
    if(*pa<=*pb)
        {
            *pc++=pa++;
        }
        else
        {
            *pc++=pb++;
        }
    }
    while(pa<=pa_last)
        {
            *pc++=*pa++;//插入La得剩余元素
        }
    while(pb<=pb_last)
        {
            *pc++=*pb++;//插入La得剩余元素
        }



}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值