数据结构笔记——第一章 线性表

2.1 线性表抽象数据类型

线形表:一种可以在任意位置进行插入和删除数据元素操作的、由n(n>=0)个相同类型数据元素a0,a1,a2,……,a(n-1)组成的线性结构。

线性表可以用顺序存储结构(顺序表)和链式存储结构(链表)存储。

 

线性表的抽象数据类型:数据集合和操作集合

数据集合:线性表的数据集合可以表示为a0,a1,a2,……,a(n-1)或a1,a2,a3,……,a(n),每个数据元素的数据类型为抽象数据类型DataType.

操作集合:                                                   

  1. 初始化ListInitiate(L)
  2. 求当前数据元素个数ListLength(L)
  3. 插入数据元素ListInsert(L,i,x) :在线性表L的第i个数据前插入数据元素x

约束条件0<=i<= ListLength(L)-1 分析i:当i=0表示在a0前插入数据元素x;当i= ListLength(L)-1表示在a(ListLength(L)-1)后插入数据元素x

  1. 删除数据元素ListDelete(L,i,x):删除线性表L的第i个数据元素,所删除数据由参数x带回,删除成功返回1,否则返回0

约束条件0<=i<= ListLength(L)-1 分析i:当i=0表示删除数据元素a0,所删除数据由参数x带回;当i= ListLength(L)-1表示删除数据元素a(ListLength(L)-1)

  1. 取数据元素ListGet(L,i,x):取出线性表L的第i个数据元素,所取数据由参数x带回,取出成功返回1,否则返回0

约束条件0<=i<= ListLength(L)-1 分析i:当i=0表示取数据元素a0;当i= ListLength(L)-1表示取数据元素a(ListLength(L)-1)

 

2.2 线性表的顺序表示和实现

顺序表的存储结构P29

定义结构体SeqList:

typedef struct

{

       DataType list[MaxSize];  /*存放数据的数组元素成员*/

       int size;                /* 记录数组当前个数的成员*/

}SeqList;                   /*命名该结构体为SeqList*/

 

 

 

顺序表

顺序表操作的实现(P30~P32):

(1)顺序表初始化

void ListInitiate(SeqList *L)      /*初始化函数*/

{

       L->size=0;               /*初始化数据元素个数*/

}

(2)求数组当前元素个数

int ListLength(SeqList L)    /*求数组当前元素个数函数*/

{

       return L.size;

}

 

(3)插入数据元素

/*在数组的位置i(0<=i<=size)前插入数组元素x函数*/

/*插入成功时函数返回1,否则返回0*/

int ListInsert(SeqList *L,int i,DataType x)

{

       int j;

       if(L->size>=MaxSize)

       {

              printf("数组已满无法插入!\n");

              return 0;

       }

       else if(i<0||i>L->size)

       {

              printf("参数i不合法!\n");

              return 0;

       }

       else

       {

              /*为插入做准备*/

              for(j=L->size;j>i;j--)

                     L->list[j]=L->list[j-1];

              L->list[i]=x;

              L->size++;       /*元素个数加1*/

              return 1;

       }

}

(4)删除数据元素

/*删除数组中第i个位置数据并存放到x中*/

/*删除的数组的值存于参数x中。取数据成功时返回1,否则返回0*/

int ListDelete (SeqList *L,int i,DataType *x)

{

  Int j;

  If(L->size<=0)

{

printf(“顺序表已空无数据元素可删!\n”);

return 0;

}

else if(i<0||i>L->size-1)

{

  printf(“参数i不合法!”);

return 0;

}

else

{

  *x=L->list[i];     /*保存删除的元素到x中*/

  for(j=i+1;j<=size-1;j++)  /*依次前移*/

  L->list[j-1]=L->list[j];

  L->size--;            /*数据元素个数减1*/

return 1;

}

}

(5)取出数据元素

/*取数组中第i个位置数据的函数*/

/*取到的数组的值存于参数x中。取数据成功时返回1,否则返回0*/

int ListGet(SeqList L,int i,DataType *x)

{

       if(i<0||i>L.size-1)

       {

              printf("参数i不合法!\n");

              return 0;

       }

       else

       {

              *x=L.list[i];

              return 1;

       }

}

 

 

顺序表操作的效率分析(P33)

插入和删除的时间复杂度最高为O(n);其他操作与元素个数n无关,时间复杂度为O(1)

向线性表中插入一个数据元素需移动的数据元素的平均次数为n/2,

向线性表中删除一个数据元素需移动的数据元素的平均次数为(n-1)/2

 

顺序表的优缺点:

优点:算法简单,空间单元利用效率高

缺点:需预先确定元素个数,插入和删除操作需要移动较多的数据元素

 

顺序表的应用(P33)

 

2.3线性表的链式表示和实现

指针:指向物理存储单元地址的变量

结点:数据元素域和一个或若干个指针域组成的一个结构体

 

单链表:构成链表的结点只有一个指向直接后继结点的指针域

表示方法:

数据域

指针域

data

next

存放数据元素

存放下一结点的指针

存放数据元素

存放下一结点的指针

 

头指针:指向单链表的指针

头结点:头指针所指的不存放数据元素的第一个结点

 

带头结点单链表和不带头结点单链表的比较P38~P40

单链表

单链表的操作实现

 

定义单链表结点的结构体:

typedef struct Node

{

   DataType data;

   struct Node* next;

} SLNode;

 

(1)初始化ListInitiate(SLNode * *head)

void ListInitiate(SLNode * *head)

{

       if( ( *head = (SLNode*)malloc(sizeof(SLNode)) )==NULL)/*如果有内存空间,申请头指针空间并使头指针head指向头结点*/

               exit (1);

         (*head)->next=NULL;     /*置结束标记NULL*/

}

 

(2)求当前数据元素个数

int ListLength(SLNode *head)

{

       SLNode *p=head;               /**/

       int size=0;

       while(p->next!=NULL)

       {

              p=p->next;

              size++;

       }

       return size;

}

 

(3)插入ListInsert(SLNode *head,int i,DataType x)

int ListInsert(SLNode *head,int i,DataType x)

{

       SLNode *p,*q;

       int j;

       p=head;

       j=-1;

       while(p->next!=NULL&&j<i-1)

       {

              p=p->next;

              j++;

       }

       if(j!=i-1)

       {

              printf("插入位置参数错误!");

              return 0;

       }

       if((q=(SLNode*)malloc(sizeof(SLNode)) )==NULL)

              exit (1);

       q->next=p->next;

       p->next=q;

       return 1;

}

 

(4)删除ListDelete(SLNode *head,int i,DataType *x)

int ListDelete(SLNode *head,int i,DataType *x)

{

       SLNode *p,*s;

       int j;

       p=head;

       j=-1;

       while(p->next!=NULL&&p->next->next!=NULL&&j<i-1)

       {

              p=p->next;

              j++;

       }

       if(j!=i-1)

       {

              printf("删除位置参数错!");

              return 0;

       }

       s=p->next;

       *x=s->data;

       p->next=p->next->next;

       free(s);

       return 1;

}

 

(5)取数据元素ListGet(SLNode *head,int i,DataType *x)

int ListGet(SLNode *head,int i,DataType *x)

{

       SLNode *p;

       int j;

       p=head;

       j=-1;

       while(p->next!=NULL&&j<i)

       {

              p=p->next;

              j++;

       }

       if(j!=i-1)

       {

              printf("取元素位置参数错!");

              return 0;

       }

       *x=p->data;

       return 1;

}

 

(6)撤销单链表Destroy(SLNode **head)

void Destroy(SLNode **head)

{

       SLNode *p,*p1;

       p=*head;

       while(p!=NULL)

       {

              p1=p;

              p=p->next;

              free(p1);

       }

       *head=NULL;

}

 

 

单链表操作的效率分析(P45)

单链表的求数据元素个数操作的时间复杂度为O(n)

向单链表中插入一个数据元素需移动的数据元素的平均次数为n/2,

向单链表中删除一个数据元素需移动的数据元素的平均次数为(n-1)/2

 

单链表的优缺点

优点:不需要预先确定元素个数的最大个数

缺点:算法复杂,每个结点中要有一个指针域,空间单元利用率不高

 

单链表应用举例P(45)

 

循环链表:单链表的另一种形式,链表中最后一个结点的指针域为链表的第一个结点

差别:

  1. 初始化函数中,(*head)->next=NULL改为(*head)->next=head
  2. 其他函数中,循环条件p->next!=NULL和p->next->next!=NULL中NULL改为head

 

 

双向链表:每个结点除后置指针域外还有一个前驱指针域

双向链表结点的结构体定义:   prior           data          next

 

 

 

 

type struct Node

{

    DataType data;

    struct Node *next;

    struct Node *prior;

} DLNode;

 

双向链表的操作实现:P48~P51

  1. 初始化
  2. 插入数据元素
  3. 删除数据元素
  4. 撤销内存空间

 

2.4 静态链表 P51

2.5 算法设计举例 P52~P55

顺序表:

 

单链表:

猜你喜欢

转载自blog.csdn.net/qq_40270579/article/details/81099219
今日推荐