線性表-順序表

數據結構的運算是建立在邏輯結構層次上的,而運算的具體實現是建立在存儲結構上的。

抽象數據結構定義為

ADT Linear_List
{ 
  數據對象:任意數據元素的集合D={a|任意數據元素}
  數據關系:除頭元素和尾元素外,其它元素均有一個直接的前驅和一個直接的后繼
}ADT Linear_List

線性表的順序存儲結構

數據結構在內存中的存儲通常有兩種:順序存儲(又稱順序表)和鏈式存儲(又稱鏈表)。

順序表

  • 圖示


    image.png

特點:各元素用一塊地址連續的存儲空間,邏輯上相鄰的元素物理存儲上也相鄰。
地址的計算公式(第i個元素的地址):
Loc(ai)=Loc(a1)+(i-1)d
其中:1≤i≤n,d是每個元素所占的地址大?。ㄍǔ樽止潝担?br> 如:設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);//插入后的遍歷
}

優缺點

  • 優點:元素的位置容易確定(依據數組的下標)。所以生成和遍歷可以順序(或倒序)和隨機進行。
  • 缺點:由于邏輯相鄰的元素物理存儲上也相鄰,所以需要一片連續的存儲單元;插入和刪除會引起前后大量元素的移動,又由于通常是用數組來存放,而數組事先要確定長度(靜態)。如果數組長度確定過小,插入時容易造成溢出;如果數組長度確定過大,刪除過多的元素造成存儲浪費。
    這種機制有點像我們以前走過的“計劃經濟”過程。
    下面介紹的鏈式存儲可以解決這種不足。從“計劃經濟”轉變為“市場經濟”。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容