线性表-顺序表

数据结构的运算是建立在逻辑结构层次上的,而运算的具体实现是建立在存储结构上的。

抽象数据结构定义为

ADT Linear_List
{ 
  数据对象:任意数据元素的集合D={a|任意数据元素}
  数据关系:除头元素和尾元素外,其它元素均有一个直接的前驱和一个直接的后继
}ADT Linear_List

线性表的顺序存储结构

数据结构在内存中的存储通常有两种:顺序存储(又称顺序表)和链式存储(又称链表)。

顺序表

  • 图示


    image.png

特点:各元素用一块地址连续的存储空间,逻辑上相邻的元素物理存储上也相邻。
地址的计算公式(第i个元素的地址):
Loc(ai)=Loc(a1)+(i-1)d
其中:1≤i≤n,d是每个元素所占的地址大小(通常为字节数)
如:设Loc(a1)的起始地址是0011,d=2(字节)
Loc(a2)=Loc(a1)+(2-1)d=Loc(a1)+d=0011+2=0013

  • C语言定义
    在C语言中,对顺序表显然用数组存储比较适宜。
#define MAXSIZE 100 //选择足够大的空间
typedef int ElemType; //ElemType是int类型的一个别名
typedef struct node
{ 
    ElemType data[MAXSIZE];//存储各表元素
    int length; //表长
} SeqList; //顺序表的类型

SeqList L;//L为顺序表(结构体变量)
image.png

注意:
元素次序为:1,2,3,……,i
C语言中数组元素的下标次序为:0,1,2,……,i-1

若用L(结构体变量)表示:
第i个元素自身:L.data[i-1] 
前驱是:L.data[i-2]
后继是:L.data[i]
表长:L.length 

基本操作

1.顺序表的初始化

  • SeqListInit(L) //初始化操作,构造一个空表
void SeqListInit(SeqList L) 
{
 L.length=0; //将顺序表长度置0
}

2.顺序表求长度

  • SeqListLength(L) //求表长
 int SeqListLength(SeqList L) 
{
  return(L.length); //返回顺序表的长度
}

时间复杂度:O(1)

3.顺序表取元素

  • SeqListGet(L,i) //取元素
ElemType SeqListGet(SeqList L,int i) 
{
 if(i>=1&&i<=L.length) //i值是否合法
   return(L.data[i-1]); //返回该元素
  else {printf(“i值不合法”);exit(0);}
}

时间复杂度:O(1)

4.顺序表元素的定位操作

  • SeqListLocate(L,x) //查找元素
int SeqListLocate(SeqList L,ElemType e) 
{
  i=1;
while(i<=L.length&&e!=L.data[i-1])i++;
   if(i<=L.length)return(i); 
   else {printf(“此元素不在表中”);exit(0);}
}

时间复杂度:O(n)
  1. 顺序表求前驱操作
  • SeqListPrior(L,e) //求元素的前驱
ElemType SeqListPrior(SeqList L,ElemType e)
{
  i=SeqListLocate(L,e);
    if(i==1){printf(“第一个元素没有前驱”);
  exit(0);}
    else return(L.data[i-2]);//返回该元素的前驱
}

时间复杂度:O(n)
  1. 顺序表求后继操作
  • SeqListPrior(L,e) //求元素的后继
ElemType SeqListPrior(SeqList L,ElemType e) 
{
  i=SeqListLocate(L,e);
   if(i==L.length)
{printf(“最后一个元素没有后继”);
exit(0);}
   else return(L.data[i]);//返回该元素的后继
  }

时间复杂度:O(n)

7.顺序表的前插操作

  • SeqListInsert(L,i,e) //前插元素
    在表的第i的位置之前插入一个值为b的新元素,使表长变为L.length+1
    操作步骤:
    (1)检查插入要求的合理性
    (2)将至顺序向后挫动,为新元素b让出位置
    (3)将b插入空出的第i的位置
    (4)修改表长的值L.length+1
void SeqListInsert(SequList L,int i,ElemType b)
{
  int j;
  if(L.length==MAXSIZE)
    {printf("表满,无法插入");exit(0);}
  if(i<1||i>L.length)
    {printf("插入位置i非法");exit(0);}
  for(j=L.length-1;j>=i-1;j--)
    L.data[j+1]=L.data[j]; // 元素后移
    L.data[i-1]=b; // 在第i个位置上插入b
    L.length++; // 表长加1
}

时间复杂度为O(n)

8.顺序表的删除

  • ListDelete(L,i) //删除元素
    将表的第i个元素从表中删除,使原表长L.length-1
    删除步骤如下:
    (1) 检查删除要求的合理性
    (2)将至顺序向前移动挤掉(删除)
    (3) 修改表长的值L.length-1。
void SeqListDelete(SeqList L,int i)
{ 
  int j;
     if(i<1||i>L.length)
      {printf("删除位置i非法");exit(0);}
      for(j=i;j<=L.length-1;j++)
        L.data[j-1]=L.data[j]; // 元素前移
    L.length--; // 表长减1
}

时间复杂度为O(n)

9.顺序表判空操作

  • ListEmpty(L) //判空表
int SeqListEmpty(SeqList L) 
{
 return(!L.length);//L.length==0
}

10.顺序表的遍历

  • SeqListTraverse(L) //遍历
void SeqListTraverse(SeqList L)//遍历
{ 
  int i;
  if(SeqListEmpty(L))printf(“空表”);
    // SeqListEmpty(L)==1
  else for(i=1;i<=L.length;i++)
    printf("%5d",L.data[i-1]);
}

说明:以上操作只是表的基本操作,绝不是表的全部操作。

11.顺序表的创建

void SeqListcreat(SeqList L) // 创建
{
    int i=0;
    ElemType x;
    printf("创建顺序表,输入若干整数,-1作为结束: ");
    scanf("%d",&x);
    while(x!=-1)
    {
        L.data[i]=x;
        scanf("%d",&x);
        i++;
    }
    L.length=i; // 记录数据个数(即表长)
}

运用

一、 顺序表的创建、遍历插入和删除

#define MAXSIZE 100
#include<stdio.h>
typedef int ElemType;
typedef struct
{
    ElemType data[MAXSIZE];
    int length;
} SeqList;

SeqList L;

int empty(void) //判空表
{
 return(!L.length);
}

void creat(void) // 创建
{
    int i=0;
    ElemType x;
    printf("创建顺序表,输入若干整数,-1作为结束: ");
    scanf("%d",&x);
    while(x!=-1)
    {
        L.data[i]=x;
        scanf("%d",&x);
        i++;
    }
    L.length=i; // 记录数据个数(即表长)
}

void visit(void)//遍历
{
   int i;
   if(empty())printf("空表");
   else 
      for(i=1;i<=L.length;i++)printf("%5d",L.data[i-1]);
   printf("\n表长是:%d\n\n",L.length);
}

void insert(int i,ElemType b)//插入
{
   int j;
   if(L.length==MAXSIZE)printf("表满,无法插入");
   if(i<1||i>L.length)
    {printf("插入位置i非法\n");exit(0);}
   for(j=L.length-1;j>=i-1;j--)L.data[j+1]=L.data[j]; 
      // 元素后移
     L.data[i-1]=b; // 在第i个位置上插入b
     L.length++; // 表长加1
}  

void deletes(int i)//删除
{ 
  int j;
  if(i<1||i>L.length)
    {printf("删除位置i非法\n");exit(0);}
  for(j=i;j<=L.length-1;j++)L.data[j-1]=L.data[j]; 
    // 元素前移
    L.length--; // 表长减1
}

void main()
{
  int i;ElemType x;
  creat();//创建
  printf("创建后的顺序表L: ");visit();//创建后的遍历
  printf("输入插入位置int i和数据int x: ");
  scanf("%d%d",&i,&x);
  insert(i,x);//插入
  printf("插入后的顺序表L: ");visit();//插入后的遍历
  printf("输入删除位置int i: ");scanf("%d",&i);
  deletes(i);//删除
  printf("删除后的顺序表L: ");visit();//删除后的遍历
}

二、 已知顺序表的数据元素递增有序,在表中插入一个数据后仍保持顺序表有序。

// 输入若干数据,先变为递增有序顺序表,再在表中插入一个元素,并仍保持递增有序。
#define MAXSIZE 100
#include<stdio.h>
typedef int DataType;
typedef struct node
{
  DataType data[MAXSIZE+1];
  int last;
} SequList;

void Creat(SequList *a) //创建顺序表
{
  DataType x;
  int i=0;
  printf("创建顺序表,输入若干整数(int),-1作为结束: ");
  scanf("%d",&x); // 输入第一个数据
  while(x!=-1)
  {
    i++;
    a->data[i]=x;
         scanf("%d",&x); // 输入下一个数据
   }
    a->last=i; // 记录数据个数(即表长)
}

void Sort(SequList *a) //顺序表排序
{
  int i,j;
  DataType temp;
  for(i=1;i<a->last;i++)//选择排序
     for(j=i+1;j<=a->last;j++)
     if(a->data[i]>a->data[j])
          temp=a->data[i],
          a->data[i]=a->data[j],
          a->data[j]=temp;  
}
void OrdInsert(SequList *a,DataType value)//插入一个元素
{
  int i,pos=1;//从第一个元素开始
  a->data[a->last+1]=value;//设置监视哨
  while(value>a->data[pos])pos++;
    //查找插入位置
    for(i=a->last;i>=pos;i--)
      a->data[i+1]=a->data[i];//数据元素移动
      a->data[pos]=value;//插入数据
      a->last++;//修改表长
}

void Visit(SequList L)//遍历顺序表
{
  int i;
  for(i=1;i<=L.last;i++)
    printf("%5d",L.data[i]);
    printf("\n\n");
}

void main()
{
  DataType value;
  SequList L;
  Creat(&L);//创建顺序表
  printf("创建后的顺序表:");Visit(L);
  Sort(&L);
  printf("排序后的顺序表:");Visit(L);
  printf("输入要插入的数据int value: ");
  scanf("%d",&value);
  OrdInsert(&L,value);//插入
  printf("插入后的链表:");
  Visit(L);//插入后的遍历
}

优缺点

  • 优点:元素的位置容易确定(依据数组的下标)。所以生成和遍历可以顺序(或倒序)和随机进行。
  • 缺点:由于逻辑相邻的元素物理存储上也相邻,所以需要一片连续的存储单元;插入和删除会引起前后大量元素的移动,又由于通常是用数组来存放,而数组事先要确定长度(静态)。如果数组长度确定过小,插入时容易造成溢出;如果数组长度确定过大,删除过多的元素造成存储浪费。
    这种机制有点像我们以前走过的“计划经济”过程。
    下面介绍的链式存储可以解决这种不足。从“计划经济”转变为“市场经济”。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容