《大话数据结构》读书笔记--第3章 线性表

3.2 线性表的定义

  1. 零个或多个数据元素的有限序列
  2. 线性表元素的个数 n(n>=0) 定义为线性表的长度,n=0,称为空表。

3.3 线性表的抽象数据类型

ADT 线性表(List)
Data
Operation
   InitList(*L); 初始化,建立空表 L
   ListEmpty(L); 是否为空
   ClearList(*L); 清空
   GetElem(L,i,*e);将表中第i个位置元素赋值给 e
   LocateElem(L,e);查找
   ListInsert(*L,i,e);第i个位置插入e
   ListLength(L); 元素个数
//将 Lb 元素插入到 La 中
void union(List *La,List Lb) {
    int La_len,Lb_len,i;
    ElemType e;
    La_len = ListLength(La);
    Lb_len = ListLength(Lb);
    for(i = 0;i< Lb_len; i++) {
        GetElem(Lb,i,e);//将表中第i个位置元素赋值给 e
        if(!LocateElem(La,e)){//判断是否存在
           ListInsert(La,++La_len,e);//插入
        }
    }
}

3.4 线性表的顺序存储结构

3.4.1 顺序存储的定义

  1. 用一段地址连续的存储单元依次存储线性表的数据元素。
  2. 用一段连续的内存地址存储数据元素。

3.4.2 顺序存储方式

  1. 一维数组实现顺序存储结构
#define MAXSIZE 20
typedef int ElemType;
typedef struct {
  ElemType data[MAXSIZE]; //数组存储元素
  int length;         //长度
}SqList;

3.4.3 数组长度和线性表长度区别

  1. 数组长度:存放线性表的存储空间长度
  2. 线性表长度:线性表中数据元素个数

3.4.4 地址计算方法

  1. 存储器中每个存储单元都有自己的编号,这个编号称为地址。
  2. LOC(ai+1) = LOC(ai) + c(c 个存储单元)

3.5 顺序存储结构的插入与删除

3.5.1 获取元素操作

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
Status GetElem(SqList L,int i,ElemType *e){
    if(L.length == 0 || i < 0 || i > L.length - 1) {
        return ERROR;
    }
    *e = L.data[i];
    return OK;
}

3.5.2 插入操作

Status ListInsert(SqList *L,int i,ElemType e){
   int k;
   if(L->length == MAXSIZE || i < 0 || i > L->length - 1) {
      return ERROE;  
   }
   //不是末尾插入
   if(i < L->length - 1){
      for(k = L->length; K > i-1; k--){
          L->data[k+1] = L->data[k];      
      }
   }
   L->data[i] = e;
   L->length++;
   return OK; 
}

3.5.3 删除操作

Status ListDelete(SqList *L,int i,ElemType *e){
   int k
   if(L->length == 0 || i < 0 || i > L->length - 1) {
      return ERROE;  
   }
   *e = L->data[i];
   if(i < L->length-1){
      for(k = i; k < L->length - 1;k++){
         L->data[k-1] = L->data[k]; 
      }
   }
   L->length--;
   return OK;
}

线性表顺序存储结构的优缺点

  1. 优点
    1.无序为表中元素的逻辑关系增加额外的存储空间
    2.可以快速存取表中任一位置的元素
  2. 确定
    1.插入、删除操作需要移动大量的元素
    2.线性表长度变化较大是,难以确定存储空间容量
    3.造成存储空间的碎片。

3.6 线性表的链式存储结构

3.6.1 顺序存储结构不足的解决办法

  1. 确点:插入和删除需要移动大量的元素,耗费时间。

3.6.2 线性表链式存储结构定义

  1. 结点:数据域(数据信息)+ 指针域
  2. 链表中第一个结点的存储位置叫做头指针。
  3. 单链表的第一个结点前附设一个结点,叫头结点(可存储线性表长度等公共数据 + 头指针)

3.6.3 头指针与头结点的异同

头指针 头结点
1.链表中指向第一个结点的指针,若有头结点,则指向头结点的指针;2.头指针具有表示作用,冠以链表名字;3.头指针不为空,是必要元素 1.放在第一元素的结点之前,数据域一般无意义;2.有了头结点,对在第一元素结点前插入节点和删除第一结点,其操作与其他结点的操作就统一了;3.不是必要的

3.6.4 线性表链式存储结构代码描述

//链表定义
typedef struct Node
{
  ElemType data;
  struct Node *next;
} Node;
typedef struct Node *LinkList;

3.7 单链表的读取

Status GetElem(LinkList L;int i,ElemType *e){
   int j;
   LinkList p; //声明一个结点
   p = L->next; //p 指向链表 L 的第一个结点
   j = 0;
   while(p && j < i){ // p 不为空,j 还没 等于 i 时候
      p = p->next; //让p指向下一个结点
      ++j;
   }
   if(!p || j > i){
      return ERROR; //第 i 个元素不存在
   }
   *e = p->data; 
  return OK; 
}

3.8 单链表的插入与删除

//1.插入
State ListInsert(LinkLisk *L,int i,ElemType e){
  int j;
  LinkList p,s;
  p = *L; //p 指向链表 L 的第一个结点
  j = 0;
  while(p && j < i){ //循环
     p = p->next;
     ++j;
  }
  if(!p || j > i){ //第i个元素不存在
     return ERROR;
  }
  s = (LinkList)malloc(sizeof(Node)); //生成新结点
  s->data = e;
  s->next = p->next;
  p->next = s;
  return OK; 
}
//2.删除
State ListDelete(LinkLisk *L,int i,ElemType *e){
  int j;
  LinkList p,q;
  p = *L; //p 指向链表 L 的第一个结点
  j = 0;
  while(p->next && j < i){ //循环
     p = p->next;
     ++j;
  }
  if(!(p->next) || j > i){ //第i个元素不存在
     return ERROR;
  }
  q = p->next;
  p->next = q->next;
  *e = q->data; 
  freen(q);
  return OK; 
}

3.9 单链表的整表创建

  1. 声明一结点 p 和计数器变量 i;
  2. 初始化一空链表 L
  3. 让 L 的头结点的指针指向 NULL,j建立一个带头结点的单链表
  4. 循环
    4.1.生成一个新结点赋值给p;
    4.2.随机生成数字赋值给p的数据域p->data;
    4.3.将p插入到头结点和前一新结点之间
//随机产生 n 个元素,简历带表头结点的单链表线性表 L (头插法)
void CreateListHead(ListList *L,int n){
   LinkList p;
   int i;
   srand(time(0)); //产生随机数种子;
   *L = (LinkList)malloc(sizeof(Node));
   (*L)->next = null;
   for (i = 0;i < n;i++){
     p = (LinkList)malloc(sizeof(Node));
     p->data = rand() % 100 + 1;
     p->next = (*L) ->next;
     (*L)-> next = p;
   }
}
//L p L->next

//随机产生 n 个元素,建立带表头结点的单链表线性表 L (尾插法)
void CreateListHead(ListList *L,int n){
   LinkList p,r;
   int i;
   srand(time(0)); //产生随机数种子;
   *L = (LinkList)malloc(sizeof(Node));
   r = *L;
   for (i = 0;i < n;i++){
     p = (LinkList)malloc(sizeof(Node));
     p->data = rand() % 100 + 1;
     r->next = p; //将表尾终端结点的指针指向新结点
     r = p;  //将当前的新结点定义为表尾终端结点
   }
   r->next = NULL;//当前链表结束
}
//r r->next(p)

3.10 单链表的整表删除

  1. 声明一结点p和q;
  2. 将第一结点赋值给 p;
  3. 循环;
    3.1.将下一个结点赋值给 q;
    3.2.释放 p;
    3.3.将 q 赋值给 p
Status ClearList(LinkeList *L){
  LinkList p,q;
  p = (*L)->next;
  while(p){
    q = p->next;
    free(p);
    p=q;
  }
  (*L)->next = NULL;
  return OK;
}

3.11 单链表结构与顺序存储结构优缺点

在这里插入图片描述

3.12 静态链表

  1. 用数组描述的链表叫做静态链表
#define MAXSIZE 1000
typedef struct{
  ElemType data;
  int curr;
}Component,StaticLinkList[MAXSIZE];
  1. 未被使用数组元素称为链表,数组第一个元素,下标0的元素的 cur,存放第一个备用链表的第一个结点小,最后一个元素存放第一个有数值元素的下标。
0 1  2  3  4  5  6  7  8
  甲 乙
cur
3 2  0  4   5          1   

3.12.1 静态链表的插入操作

int Malloc_SLL(StaticLinkList space){
   int i = space(0).cur;
   if(space[0].cur){
      space[0].cur = space[i].cur;
   }
   return i;
}

Status ListInsert(StaticLinkList l,int i, ElemType e){
   int j,k,l;
   k = MAXSIZE - 1;//k首先是最后一个元素的下标 999
   if(i < 1 || i> ListLength(L) + 1){
      return ERROR;
   }
   j = Malloc_SLL(L);//获取空闲分量的下标 8
   if(j) {
     L[j].data = e;
     for(l = 1;l<= i-1;l++){ //找到第 i 个元素之前的位置
       k = L[k].cur;  //1 2
     }
     L[j].cur = L[k].cur;
     L[k].cur = j;
     return OK;
   }
  return ERROR;
}

在这里插入图片描述

3.12.2 静态链表删除操作

void Free_SSL(StaticLinkList space,int k){
  space[k].cur = space[0].cur;
  space[0].cur = k;
}

Status ListDelete(StaticLinkList L,int i){
   int j,k;
   if(i<1 || i > ListLength(L)){
      return ERROE;
   }
   k = MAXSIZE - 1;
   for(j = 1;j<= i-1;j++){
     k = L[k].cur;  //1 2
   }
   j = L[k].cur;
   L[k].cur = L[j].cur;
   Free_SSL[L,j];
   return OK;
}
int ListLength(StaticLinkList L){
  int j = 0;
  int i =L[MAXSIZE-1].cur;
  while(i){
    i = L[i].cur;
    j++;
  }
  return j; 
}

在这里插入图片描述

3.12.3 静态链表优缺点

  1. 优点:插入和删除,只需要修改游标,不需要移动元素,从而改进了顺序存储结构中插入和删除操作需要移动大量元素的缺点。
  2. 缺点:没有解决连续存储分配带来的表长难以确定的问题;失去了顺序存储结构随机存取的特性。

3.13 循环列表

  1. 将单链表中终端结点的指针端有空指针改为指头指针,是单个链表形成一个环。
  2. 使用尾指针

3.14 循环列表

  1. 双向链表在单链表的每一个结点中,再设置一个指向前驱结点的指针域。
typedef struce DulNode{
  ElemType data;
  struct DulNode *prior;
  struct DulNode *next;
}
发布了40 篇原创文章 · 获赞 14 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_44947117/article/details/104173883