第二章 线性表

本文详细介绍了线性表的基础概念,包括线性表的定义、特点和两种主要的存储结构——顺序表和链表。顺序表采用连续的存储空间,支持随机访问,而链表则利用指针链接元素,便于动态扩展。文中还提供了顺序表的C++实现,包括初始化、插入、删除、查找等基本操作,并展示了如何在实际应用中使用这些操作。

线性表

基础概念

定义:线性表是具有相同特征数据元素的一个有限序列,该序列中所含元素的个数叫线性表的长度。一个线性表中的元素个数n(n>=0)定义为线性表的长度,n=0时称为空表,非空线性表中的每个元素都有一个确定的位序

线性表中的元素之间的关系是线性关系

  • 存在唯一的一个第一个元素(表头元素,表头元素没有前驱)
  • 存在唯一的一个最后一个元素(表尾元素,表尾元素没有后继)
  • 除了第一个元素之外,每个元素均只有一个直接前驱
  • 除了最后一个元素之外,每个元素均只有一个直接后继

线性表的存储结构:线性表的存储结构有顺序存储结构链式存储结构两种,前者称为顺序表,后者称为链表

**顺序表:**顺序表就是把线性表中所有的元素按照其逻辑顺序,依次存储到从指定的存储位置开始的一块连续的存储空间中。

顺序表的特点:(考试中经常会出现的选择题)

  • 存储单元地址连续(需要一段连续的空间)
  • 逻辑上相邻的数据元素其物理位置也相邻
  • 存储密度大(100%)
  • 能够随机存取(随机访问)

**链表:**在链表存储中,每个结点不仅包含所有元素的信息,还包含元素之间逻辑关系的信息

链表表的特点:(考试中经常会出现的选择题)

  • 链表支持存储空间的动态分配
  • 链表不支持随机访问
考试中经常考到的顺序表和链表的比较
  1. 存储分配方式:顺序表的存储空间是一次性分配的,容易造成存储空间的浪费;链表的存储空间是多次分配的(顺序表必须用一片连续存储单元,链表不需要。)
  2. 存储密度(存储密度=结点值域所占存储量/结点结构所占的存储总量):顺序表的存储密度=1;链表的存储密度<1(因为结点中有指针域)
  3. 从整体来看,一般顺序表存储空间利用率低于链表,但从单个存储单元来看,顺序表存储空间利用率高于链表。
  4. 顺序表可次随机存取,链表不能随机存取
  5. 插入/删除元素时候,顺序表基本需要移动元素,链表只需要修改指针。
顺序表中基本操作的实现

定义顺序表的存储结构

#define MAXSIZE 100					//顺序表能达到的最大长度
typedef struct{
  ElemType *elem;						//存储空间的基地址
  int length;								//顺序表当前长度
}Sqlist;

顺序表初始化(为顺序表L动态分配一个预定义大小的数存储空间;使elem指向这段空间的基地址;将表的当前长度设置为0)

Status InitList(Sqlist &L){
//构造一个空的顺序表L
  L.elem = new ElemType[MAXSIZE];		//为顺序表分配一个大小为MAXSIZE的存储空间
  if(!L.elem)												//判断如果分配失败,退出
    exit(OVERFLOW);
  L.length = 0;											//让空表长度为0
  return OK;   
}

顺序表的插入(判断插入位置是否合法;判断顺序表的存储空间是否已经满了;将第n至第i个位置的元素依次向后移动一个位置,空出第i个位置;将要插入的新元素e放入第i个位置;将表长自增1)

Status ListInsert(Sqlist &L, int i, ELemType e){
  //在顺序表L中的第i个位置插入新元素e
  if ((i<1)||(i>L.length+1)		//判断输入是否合法
     return ERROR;
  if (L.length==MAXSIZE)			//判断存储空间是否已经满了
     return ERROR;
  for(j = L.length-1 ;j>=i-1 ;j--)
      L.elem[j+1] = L.elem[j];
  L.elem[i-1] = e;
  ++L.length;
  return OK;      
}

顺序表的删除(判断删除的位置i是否合法;将第i+1个至第n个元素依次向前移动一个位置,表长自减1)

Status Listdelete(Sqlist &L ,int i){
  //在顺序表L中删除第i个元素;
  if((i<1)||(i>L.length))
    return ERROR;
  for(j = i; j<=L.length-1 ;j++)
    L.elem[j-1] = L.elem[j];
  --L.length;
  return OK;
}

顺序表的查找(从第一个元素开始,依次和e进行比较,如果找到与e相等的元素L.elem[i],则查找成功)

Status Listsearch(Sqlist L, ElemType e){
  //顺序表L中查找数值为e的数据元素,返回序号.Sqlist L不需要使用引用型,可以理解为顺序表L在查找的过程中没有发生改变。
  for (i = 0; i< L.length; i++)
    if(L.elem[i]==e)
      return i+1;
  return 0;
}

顺序表的取值(判断指定的位置序号i是否合法;合理将第i个数据元素L.elem[i-1]赋值给参数e;通过e返回第i个数据算的传值)

Status GetElem(Sqlist L, int i,Elemtype &e){
  //因为e要发生改变,所以使用引用型
  if(i<1||i>L.length)
    return ERROR;
  e = L.elem[i-1];
  return OK;
}

顺序表的算法融合练习

#include <iostream>
using namespace std;

typedef int Status;
typedef int ElemType;
#define OVERFLOW 3
#define ERROR 0
#define OK 1

//顺序表的存储结构
#define MAXSIZE 100
typedef struct 
{
    ElemType *elem;
    int length;
}SqList;

SqList L;

//初始化顺序表
Status InitList(SqList &L)
{//构造一个空的顺序表L
    L.elem = new ElemType[MAXSIZE];
    if(!L.elem)
        exit(OVERFLOW);
    L.length = 0;
    return OK;
}

//顺序表销毁
Status DestroyList(SqList &L)
{
    delete []L.elem;
    L.elem = NULL;
    L.length = 0;
    return OK;
}

//顺序表清空
Status ClearList(SqList &L)
{
    L.length = 0;
    return OK;
}

//顺序表空表
Status ListEmpty(SqList L)
{
    if(L.length == 0)
        return OK;
    return ERROR;
}

//顺序表表长
Status ListLength(SqList L)
{
    return L.length;
}

//顺序表取值 O(1)
Status GetElem(SqList L, int i, ElemType &e)
{
    if(i < 1 || i > L.length)   //判断i值是否合理,若不合理,返回ERROR
        return ERROR;
    e = L.elem[i - 1];          //elem[i - 1]储存第i个数据元素
    return OK;
}

//顺序表查找 O(n)
Status LocateElem(SqList L, ElemType e)
{//顺序表中查找值为e的元素,返回其序号
    for(int i = 0; i < L.length; i++)
        if(L.elem[i] == e)
            return i + 1;
        return ERROR;
}

//顺序表前驱
Status PriorElem(SqList L, ElemType cur_e, ElemType &pre_e)
{
    for(int i = 0; i < L.length; i++)
        if(L.elem[i] == cur_e)
        {
            pre_e = L.elem[i - 1];
            return OK;
        }
    return ERROR; 
}

//顺序表后继
Status NextElem(SqList L, ElemType cur_e, ElemType &next_e)
{
    for(int i = 0; i < L.length; i++)
        if(L.elem[i] == cur_e)
        {
            next_e = L.elem[i + 1];
            return OK;
        }
    return ERROR;   
}

//顺序表插入 O(n)
Status ListInsert(SqList &L, int i, ElemType e)
{//在顺序表L中第i个位置之前插入新的元素e, i值的合法范围是1 <= i <= L.length+1
    if(i < 1 || i > L.length + 1)               //i值不合法
        return ERROR;
    if(L.length == MAXSIZE)                 //当前存储空间已满
        return ERROR;
    for(int j = L.length - 1; j >= i - 1; j--)
        L.elem[j + 1] = L.elem[j];          //插入位置之后的元素后移
    L.elem[i - 1] = e;                      //将新元素e放在第i个位置
    L.length++;                             //表长+1
    return OK; 
}


//顺序表删除 O(n)
Status ListDelete(SqList &L, int i)
{//在顺序表L中删除第i个元素, i值的合法范围是1<=i<=L.length
    if(i < 1 || i > L.length)
        return ERROR;                           //i值不合法
    for(int j = i; j <= L.length - 1; j++)
        L.elem[j - 1] = L.elem[j];              //被删除元素之后的元素前移
    L.length--;                                 //表长减1
    return OK;
}

//顺序表遍历 O(n)
Status TraverseList(SqList L)
{
    for(int i = 0; i < L.length; i++)
    {
        if(i == L.length - 1)
            cout<<L.elem[i]<<'\n';
        else
            cout<<L.elem[i]<<' ';
    }
    return OK;
}

int main()
{
    cout<<"----------------------顺序表----------------------"<<'\n';
    cout<<"操作0:退出程序"<<'\n';
    cout<<"操作1:建立一个顺序表,输入n个元素并输出"<<'\n';
    cout<<"操作2:查找线性表中的最大元素并输出"<<'\n';
    cout<<"操作3:在线性表的第i个元素前插入一个正整数x"<<'\n';
    cout<<"操作4:删除线性表中的第j个元素"<<'\n';
    cout<<"操作5:将线性表中的元素按升序排列"<<'\n';
    cout<<"操作6:将线性表中的元素就地逆序(只允许用一个暂存单元)"<<'\n';
    cout<<"--------------------------------------------------"<<'\n';
    int a, n, flag = 1;
    while(flag)
    {
        cout<<'\n'<<"请选择要执行的操作:";
        cin>>a;
        switch(a)
        {
            case 0:
            {
                cout<<"结束!"<<'\n';
                flag = 0;
                break;
            }
            case 1:
            {
                cout<<"请输入要建立的顺序表的元素个数:";
                cin>>n;
                cout<<"请按顺序输入这"<<n<<"个元素:";
                ElemType e;
                InitList(L);
                for(int i = 1; i <= n; i++)
                {
                    cin>>e;
                    ListInsert(L, i, e);
                }
                cout<<"顺序表创建完毕:";
                TraverseList(L);
                break;
            }
            case 2:
            {
                int maxIndex = 0;
                for(int i = 1; i < L.length; i++)
                    if(L.elem[maxIndex] < L.elem[i])
                        maxIndex = i;
                cout<<"线性表中的最大元素为:"<<L.elem[maxIndex]<<'\n';
                break;
            }
            case 3:
            {
                int i, x;
                cout<<"在线性表的第i个元素前插入一个正整数x,请依次输入i和x的值:";
                cin>>i>>x;
                if(ListInsert(L, i, x))
                {
                    cout<<"顺序表插入完毕:";
                    TraverseList(L);
                }
                else
                    cout<<"顺序表插入不合法!"<<'\n';
                break;
            }
            case 4:
            {
                int j;
                cout<<"删除线性表中的第j个元素,请输入j的值:";
                cin>>j;
                if(ListDelete(L, j))
                {
                    cout<<"顺序表删除完毕:";
                    TraverseList(L);
                }
                else
                    cout<<"顺序表删除不合法!"<<'\n';
                break;
            }
            case 5:
            {
                for(int i = 0; i < L.length - 1; i++)
                {
                    int minIndex = i;
                    for(int  j = i; j < L.length - 1; j++)
                    {
                        if(L.elem[minIndex] > L.elem[j + 1])
                            minIndex = j + 1;
                    }
                    int tmp = L.elem[i];
                    L.elem[i] = L.elem[minIndex];
                    L.elem[minIndex] = tmp;
                }
                cout<<"顺序表升序排列完毕:";
                TraverseList(L);
                break;
            }
            case 6:
            {
                for(int i = 0; i < L.length / 2; i++)
                {
                    int tmp = L.elem[i];
                    L.elem[i] = L.elem[L.length - i - 1];
                    L.elem[L.length - i - 1] = tmp;
                }
                cout<<"顺序表就地逆序完毕:";
                TraverseList(L);
                break;
            }
        }
    }
    return 0;
}

未完待续。。。。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值