2021-12-18 数据结构——线性表(上) (c++代码和c代码)

线性表是最基本、最简单、也是最常用的一种数据结构。==线性表(linear list)==是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。

1.基本概念

线性表:零个或多个数据元素的有限序列。
线性表:包括顺序表和链表
顺序表(数组):里面元素的地址是连续的,
链表:链表里面节点的地址不是连续的,是通过指针连起来的。

表中元素个数称为线性表的长度
线性表没有元素时,称为空表
表起始位置称为表头,表结束位置称表尾

2. 线性表的抽象数据类型

类型名称:线性表(List)
操作集:线性表 L ∈ List,整数 i 表示位置,元素 X ∈ ElementType
线性表基本操作主要有:
c格式

线性表基本操作主要有:
List MakeEmpty(): 初始化一个空线性表 L
ElementType FindKth(int K,List L):根据位序 K,返回相应元素
int Find(ElementType X,List L):在线性表 L 中查找 X 的第一次出现位置
void Insert(ElementType X,int i,List L):在位序 i 前插入一个新元素 X
void Delete(int i,List L):删除指定位序 i 的元素
int Length(List L):返回线性表 L 的长度 n

c++格式
ADT 线性表(List)
Data
线性表的数据对象集合为{a1,a2,…,an},每个元素的类型均为DataType。其中,除了第一个元素a1外,每一个元素有且只有一个直接前驱元素,除最后一个元素an外,每一个元素有且只有一个直接后继元素。数据元素之间的关系是一对一的关系。

    InitList(*L):初始化操作,建立一个空的线性表。
    ListEmpty(L):若线性表为空,返回true,否则返回falseClearList(*L):线性表清空。
    GetElem(L,i,*e):将线性表L中第i个位置元素返回给e。
    LocateElem(L,e):在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中的序列号;否则,返回0表示失败。
    ListInsert(*L,i,e):在线性表的第i个位置插入元素e。
    ListDelete(*L,i,*e):删除线性表L中的第i个元素,并用e返回其值
    ListLength(L):返回线性表L的元素个数。
    PrintList(L):打印线性表

3. 线性表的顺序存储

注意:在这里插入图片描述

3.1 顺序存储的定义

顺序表就是用数组实现,事实上就是在内存中找个初始地址,然后通过占位的形式,把一定连续的内存空间给占了,然后把相同数据类型的数据元素依次放在这块空地中。
顺序存储的大小有两种方式:一是静态分配,二是动态扩展
在这里插入图片描述

3.2 实现方式

c++模板代码:

const int MaxSize = 100;
template <class DataType>  //主要用于c++的重用性方面:template是模板的定义名称,<>号中class不是类的定义,而是相当于变量名前的类型名一样
class SeqList
{
public:
    SeqList(){length=0;}            //无参数构造方法
    SeqList(DataType a[],int n);    //有参数构造方法
    ~SeqList(){}                    //析构函数
    int Length(){return length;}    //线性表长度
    DataType Get(int i);            //按位查找
    int Locate(DataType x);         //按值查找
    void Insert(int i,DataType x);  //插入
    DataType Delete(int i);         //删除
    void PrintList();               //遍历
private:
    DataType data[MaxSize];         //顺序表使用数组实现
    int length;                     //存储顺序表的长度
};

c语言模板代码:

#include<stdio.h>
#include<malloc.h>
#define MAXSIZE 100  // MAXSIZE 定义为 Data 数组的大小
typedef int ElementType;  // ElementType 可定义为任意类型
typedef struct LNode *List; 
struct LNode{
   ElementType Data[MAXSIZE]; 
   int Last;  // Last 定义线性表的最后一个元素
};
List L;
//访问下标为 i 的元素:L->Data[i]
//线性表的长度:L->Last+1

List MakeEmpty(); //初始化顺序表 
int Find(ElementType X,List L); //查找 X 第一次出现的下标 
void Insert(ElementType X,int i,List L); //在下标为 i 的地方插入 X 
void Delete(int i,List L);   //删除下标为 i 的当前值 
ElementType FindKth(int K,List L);  //返回下标为 K 的当前值
int Length(List L);  //返回顺序表的长度

//表长
int Length(List L){
	return L->Last+1;
}

顺序表的封装需要三个属性:
1.存储空间的起始位置。数组data的存储位置就是线性表存储空间的存储位置
2.线性表的最大存储容量。数组长度MAXSIZE
3.线性表的当前长度。length

MAXSIZE和length二者区别:数组的长度与线性表的长度是不一样的。数组的长度是存放线性表的存储空间的总长度,一般初始化后不变。而线性表的当前长度是线性表中元素的个数,是会改变的

下面我们将实现顺序表的各个功能:

3.2.1 初始化

创建一个长度为n的顺序表,需要将给定的数组元素作为线性表的数据元素传入顺序表中,并将传入的元素个数作为顺序表的长度。
  在这里插入图片描述
c++

template <class DataType>
SeqList<DataType>::SeqList(DataType a[],int n)
{
    if(n>MaxSize) throw "wrong parameter";
    for(int i=0;i<n;i++)
        data[i]=a[i];
    length=n;
}

c语言

struct LNode{
   ElementType Data[MAXSIZE]; 
   int Last;  // Last 定义线性表的最后一个元素
};
//初始化 
List MakeEmpty(){
    List L;
    L = (List)malloc(sizeof(struct LNode));
    L->Last = -1;
    return L;
}
//访问下标为 i 的元素:L->Data[i]
//线性表的长度:L->Last+1

3.2.2 按位查找

按位查找的时间复杂度为O(1) 。

template <class DataType>
DataType SeqList<DataType>::Get(int i)
{
    if(i<1 && i>length) throw "wrong Location";
    else return data[i-1];
}
// 按序查找
ElementType FindKth(int K,List L){
	if(K < 0 || L->Last < K){  //位置越界
        printf("L->Data[%d]不存在元素",K);
        return;
    }
    return L->Data[K];
}

3.2.2 按值查找

按值查找,需要对顺序表中的元素依次进行比较,时间复杂度为O(n) 。

template <class DataType>
int SeqList<DataType>::Locate(DataType x)
{
    for(int i=0;i<length;i++)
        if(data[i]==x) return i+1;
    return 0;
}
// 按值查找 
int Find(ElementType X,List L){
    int i=0;
    while(i <= L->Last && L->Data[i] != X)  
        i++;
    if(L->Last < i)  //如果没找到,返回 -1
        return -1; 
    else    // 找到后返回下标 
        return i;
}

3.2.3 插入

插入的过程中需要注意元素移动的方向,==必须从最后一个元素开始移动,如果表满了,则引发上溢;==如果插入位置不合理,则引发位置异常
  在这里插入图片描述

template <class DataType>
void SeqList<DataType>::Insert(int i,DataType x)  //i不是下标,是第几个元素
{
    if(length>=MaxSize) throw "Overflow";
    if(i<1 || i>length+1) throw "Location";  //排除两边插入
    for(int j=length;j>=i;j--)
        data[j]=data[j-1];
    data[i-1]=x;
    length++;
}
// 插入
void Insert(ElementType X,int i,List L){
    int j;
    if(L->Last == MAXSIZE-1){  //位置已满 
        printf("表满");
        return;
    }
    if(i < 0 || L->Last+1 < i){  //位置越界,如果将数插入 L->Data[L->Last+1],下面都不用腾位置了 ,排除两边插入
        printf("位置不合法");
        return;
    }
    for(j=L->Last;j>=i;j--)   // 从后往前依次向后挪一个,给 a[i]腾出位置     
        L->Data[j+1] = L->Data[j];   
    L->Data[i] = X;    //新元素插入
    L->Last++;    // Last仍然指向最后元素
    return;
} 

3.2.4 删除

注意算法中元素移动方向,移动元素之前必须取出被删的元素,如果表为空则发生下溢,如果删除位置不合理,则引发删除位置异常。
在这里插入图片描述

template <class DataType>
DataType SeqList<DataType>::Delete(int i)  //i是第几个元素
{
    int x;
    if(length==0) throw "Underflow";  //一个元素也没有
    if(i<1 || i>length) throw "Location"; //越界了
    x = data[i-1];
    for(int j=i;j<length;j++)
        data[j-1] = data[j];
    length--;
    return x;
}
//删除
void Delete(int i,List L){
    int j;
    if(i < 0 || L->Last <i){  //位置越界,而删除最多到 L->Data[L->Last]
        printf("L->Data[%d]不存在元素",i);
        return;
    }
    for(j=i;j<=L->Last;j++)   // 从前往后依次向前挪一个,将 a[i] 覆盖了 
        L->Data[j-1] = L->Data[j];
    L->Last--;  // Last仍然指向最后元素
    return;
}

3.2.5 遍历

按下标依次输出各元素

template <class DataType>
void SeqList<DataType>::PrintList()
{
    for(int i=0;i<length;i++)
        cout<<data[i]<<endl;
}
for(i=0;i<Length(L);i++)
		printf("%d ",L->Data[i]);

3.2.6 实战

int main()
{
    SeqList<int> p;
    p.Insert(1,5);
    p.Insert(2,9);
    p.PrintList();
    p.Insert(2,3);
    cout<<p.Length()<<endl;
    p.PrintList();
    cout<<p.Get(3)<<endl;
    p.Delete(2);
    p.PrintList();
    return 0;
}
int main(){
	int i=0;
	L = MakeEmpty();
	Insert(11,0,L);
	printf("在线性表L-Data[0]插入11\n");
	Insert(25,0,L);
	printf("在线性表L-Data[0]插入25\n");
	Insert(33,0,L);
	printf("在线性表L-Data[0]插入33\n");
	Insert(77,0,L);
	printf("在线性表L-Data[0]插入77\n");
	printf("此时的线性表为:"); 
	for(i=0;i<Length(L);i++)
		printf("%d ",L->Data[i]);
	printf("\n");
	printf("查找值为12的下标是:%d\n",Find(12,L));
	printf("下标为3的线性表的值是:%d\n",FindKth(3,L));
	Delete(2,L);
	printf("删除线性表中下标为2的元素\n");
	Delete(2,L);
	printf("删除线性表中下标为2的元素\n");
	printf("此时的线性表为:"); 
	for(i=0;i<Length(L);i++)
		printf("%d ",L->Data[i]);
	printf("\n"); 
	return 0;
} 

4.顺序存储的优缺点

优点:
随机访问特性,查找O(1)时间,存储密度高;
逻辑上相邻的元素,物理上也相邻;
无须为表中元素之间的逻辑关系而增加额外的存储空间;
缺点:
插入和删除需移动大量元素;
当线性表长度变化较大时,难以确定存储空间的容量;
造成存储空间的“碎片”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值