数据结构学习(一)、线性表

线性表的概述

线性表拥有零个或多个数据元素的有限序列。首先它是一个序列,也就是元素之间有顺序。

线性表分为静态线性表和动态线性表,常见的有顺序线性表(静态)、单向链表(动态)、双向链表(动态)

线性表抽象数据类型定义

ADT 线性表(List)
Data
      线性表的数据对象集合为{a1,a2,···,an},每个数据类型均为DataType.另外,除第一个元素外,    其他每个元素均只有一个直接的前驱,除最后一个元素外,其他每个元素均只有一个直接的后驱。
Operation
       InitList(*L)            : 初始化线性表,建立一个空的线性表L.
       ListEmpty(L)          : 若为空,返回true ,否则返回false.
       Clear(*L)              : 清除线性表.
       GetElem(L,i,*e)      : 将线性表中的第i个元素值返回给*e.
       LocateElem(L,e)     : 在线性表中查找e.
       ListInsert(*L,i,e)    : 在L的第i个位置插入e.
       ListDelete(*L,i,*e) : 删除表L的第i个位置元素,并用e返回其值.
       ListLength(L)         : 返回线性表L的元素的个数
endADT

顺序表

c语言中的顺序存储可以用一维数组来实现。线性表的顺序存储的结构如下。

#define MAXSIZE 20
typedef int ElemType;
typedef struct{
    ElemType data[MAXSIZE];
    int length;
}SqList;

初始化操作

#define ERROR 0#define OK 1Status InitList(SqList *L){
   L->length =0;
   return OK;
}

插入操作

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

删除操作

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

获取元素操作

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

顺序线性表插入和删除操作需要移动大量的元素,并且空间无法把握,造成存储空间的“碎片”;

因此,我们干脆让所有的元素不再考虑相邻位置,哪儿有位置就到存储到哪里,但是让每个元素

都清楚它的下一个元素的位置在那里。这就是接下来要介绍的单向链表。

单向链表

单向链表的存储结构

typedef struct Node{
    ElemType data;
    struct Node *next;
} Node,*LinkList;

单链表的创建

Status InitList(LinkList *L){
   *L = (LinkList)malloc(sizeof(Node));/*给头结点分配空间*/
    if(!*L)
        exit(ERROR);
    *L->next = NULL;
    return OK;
}  

创建空头结点,这时此时后继不存在,则结点指针为空。

单链表的插入

Status ListInsert(LinkList *L,int i ,ElemType e){
     LinkList p,s;
     int j;
     p = *L;
     j = 1;
    /* 获取插入点前一个结点;*/
    while(p && j<i){
       p = p->next;
       j++;
    }
    if(!p || j>i)
       return ERROR;
    s = (LinkList)malloc(sizeof(Node));
    if(!s)
       return ERROR;
    s->data = e;
    s->next = p->next;
    p->next = s;
    return OK;
}

单链表删除操作

ElemType ListDelete(LinkList *L,int i,ElemType *e){
        LinkList p,q;
        int j;
        p = *L;
        j = 1;
        while(p && j<i){
           p = p->next;
           j++;
       }
       if(!p || j>i)
           return ERROR;
      q = p->next;
      *e = q->data;
      p->next = q->next;
      free(q);
     return OK;
}    

单向循环链表

对于单向链表,每个结点只存储了向后的结点,到了尾标志就停止了向后链的操作,无法访问它之前的结点。

因此设计了单向循环链接。

此时,我们可以用O(1)的时间访问到第一个结点,但是对于最后一个结点,却需要O(n)时间,因此,我们继续

优化单向循环链表。

如图所示,终端用尾指针rear指示,则查找终端结点是O(1),开始点,为rear->next->next也为O(1)。

单向循环链表的创建

单向循环链表的结构跟单向链表结构相同。

Status InitList(LinkList*L){
   *L = (LinkList)malloc(sizeof(Node));
   if(!*L) /* 存储分配失败 */
      exit(ERROR);
   (*L)->next = *L;
   return OK;
}

单向循环链表的长度

int ListLength(LinkList L){
      int i=0;
      LinkList p=L->next; /* p指向头结点 */
      while(p!=L) /* 没到表尾 */
      {
       i++;
       p=p->next;
      }
      return i;
}

单向循环链表插入操作

循环链表插入操作和单向链表插入操作相似,值得注意的是当向末尾插入结点时,需将尾指针指向尾结点。

Status ListInsert(LinkList *L,int i,ElemType e){
    int j;
    LinkList p,s;
    p=(*L)->next;/* p指向第1个结点 */
    j=1;
    if(i<1||i>ListLength(*L)+1)
        return ERROR;
    while(j<i){ /* 寻找第i-1个结点 */
      p=p->next;
      ++j;
    }
    s = (LinkList )malloc(sizeof(Node));
    if(!s) /* 存储分配失败 */
       exit(OVERFLOW);
    s->data=e;
    s->next=p->next;
    p->next=s;
    if(p==*L){
       *L = s;
    } /* 改变尾结点 */
    return OK;
}

单向循环链表删除操作

循环链表删除操作和单向链表删除操作相似,值得注意的是当删除末尾结点时,需将尾指针指向删除的结点的前一结点。

Status ListDelete(LinkList*L,int i,ElemType *e){
    LinkList p,q;
    int j=1;
    p = (*L)->next;
    if(i<1||i>ListLength(*L))
      return ERROR;
    while(j<i){
       p=p->next;
       j++;
    }
    q = p->next;
    *e = q->data;
    p->next = q->next;
    if(*L==q) /* 删除的是表尾元素 */
      *L=p;
    free(q);
    return OK;
}

双向循环链表

此时,处于单向循环链表的an位置,但是我想访问an-1位置的数据,我只能重新遍历一次。这样非常浪费时间,有没有更迅速的方法呢?这就是接下来介绍的双向循环链表。

双向循环链表的存储结构

typedef struct DNode{
     ElemType data;
     struct DNode *next;
     struct DNode *prior;
} DNode ,*DLinkList;

双向循环链表的创建

Status InitList(DLinkList *L){
     *L = (DLinkList)malloc(sizeof(DNode));
     if(!*L)
         exit(ERROR);
     (*L)->next  = *L;
     (*L)->data  = 222;
     (*L)->prior = *L;
     return OK;
 }

双向循环链表的长度

int ListLength(DLinkList L){
       int i=0;
       DLinkList p=L->next;
       while(p!=L) {
         i++;
         p=p->next;
       }
       return i;
 }

双向循环链表的插入

Status ListInsert(DLinkList *L,int i,ElemType e){

     int j=1,length;
     DLinkList p,s;
     p = *L;
     length = ListLength(*L);
     if(i<1 ||i>length+1)
         return ERROR;
     s = (DLinkList)malloc(sizeof(DNode));
     if(!s)
         exit(ERROR);
     while(j<i){
        p=p->next;
        j++;
     }
     s->prior  = p;
     s->data  = e;
     s->next = p->next;
     p->next->prior=s;
     p->next = s;
     return OK;
}

双向循环链表的删除

Status ListDelete(DLinkList *L,int i){
    DLinkList p,s;
    int j=0;
    p = *L;
    if(i<0 || i>ListLength(*L))
        return ERROR;
    while(j<=i){
        p=p->next;
        j++;
    }
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);
    return OK;
}
时间: 2024-11-05 14:01:30

数据结构学习(一)、线性表的相关文章

数据结构学习笔记——线性表的应用

数据结构学习笔记——线性表的应用 线性表的应用 线性表的自然连接 计算任意两个表的简单自然连接过程讨论线性表的应用.假设有两个表A和B,分别是m1行.n1列和m2行.n2列,它们简单自然连接结果C=A*B(i==j),其中i表示表A中列号,j表示表B中的列号,C为A和B的笛卡儿积中满足指定连接条件的所有记录组,该连接条件为表A的第i列与表B的第j列相等. 如:         1 2 3                3 5 A  =  2 3 3         B =  1 6       

数据结构学习笔记——线性表

第2章  线性表 2.1  线性表的类型定义  线性结构的特点是:在数据元素的非空有限集中,(1)存在唯一的一个被称做“第一个”的数据元素:(2)存在唯一的一个被称做“最后一个”的数据元素:(3)除第一个之外,集合中的每个数据元素只有一个前驱:(4)除最后一个外,集合中每个数据元素均只有一个后继. 线性表的类型定义 线性表(linear_list)是最常用的且最简单的一种数据结构.一个线性表是n个数据元素的有限序列.在稍复杂的线性表中,一个数据元素可以由若干个数据项(item)组成.在这种情况下

数据结构学习笔记-----------------线性表

线性结构的特点:在数据的非空有限集中 一.存在唯一一个被称为"第一个"的数据元素 二.存在唯一一个被称为"最后一个"的数据元素 三.除第一个之外,集合中每个数据元素均只有一个前驱 四.除最后一个之外,集合中每个数据元素均只有一个后继 一个线性表是n个数据元素的有限序列 序偶关系:两个固定次序的客体组成一个序偶,它常表达连个客体之间的关系. 非递减有序排列:从小到大,允许中间有相等的情况

python数据结构之一:线性表

线性表:零个或多个数据元素的有限序列. 咋一看这句话,我也不明白是什么意思,哈哈,举例说明一下吧.去电影院买票时,人们的排队就是一个线性表,有固定的最前一个,固定的最后一个. 张三是其中一个,他的前一个人,和后一个人是确定的单一的. 再如,一个公司里的一个部里有一个领导,多名员工,他们的关系就不是线性表了,有一对多的关系. 那么在python里如何创建线性表呢?如下: L1=["a","b","c","d","e&q

数据结构与算法--线性表系列(循环链表、双向链表)

hello,everybody,今天我们来学习线性表的最后两种形式,循环链表.双向链表.这两种链表,是链式存储结构的不同形式.书归正传,我们先来看看循环链表吧. 大家思考一个问题,我们把线性表各个元素比作下图的路线图上的城市: 我们的线性表各个结点的指针,都是指向唯一的后继结点,线性表的终端结点的指针为空.这样的话,如果我们在南京,我们需要先访问南京右j边的城市,再访问南京左边的城市.根据线性表的结构,我们只能返回上海,从上海依次访问到北京.因为我们的终端结点的指针为空,如果直接访问南京右边的城

数据结构与算法-线性表

近期在学习数据结构,反反复复已经看过几遍了,也做了一些练习题,但总感觉不记录一下,思路就不是很清晰,所以,从今天开始总结这段时间对数据结构的学习. 无论学习什么,基础知识都是最总要的,数据结构也不例外.线性表就是数据结构的基础,很多常见的数据结构都是基于线性表来实现的. 那么,什么是线性表呢?官方的定义是: 零个或多个数据元素的有限序列 可以从两个方面来理解线性表,首先它是一个序列,也就是其中的元素有先后顺序,其次是有限的,对于无线数列,也只能存在于理论数学中. 说了这么多,小结一下: 1)线性

数据结构和算法 (二)数据结构基础、线性表、栈和队列、数组和字符串

Java面试宝典之数据结构基础 —— 线性表篇 一.数据结构概念 用我的理解,数据结构包含数据和结构,通俗一点就是将数据按照一定的结构组合起来,不同的组合方式会有不同的效率,使用不同的场景,如此而已.比 如我们最常用的数组,就是一种数据结构,有独特的承载数据的方式,按顺序排列,其特点就是你可以根据下标快速查找元素,但是因为在数组中插入和删除元素会 有其它元素较大幅度的便宜,所以会带来较多的消耗,所以因为这种特点,使得数组适合:查询比较频繁,增.删比较少的情况,这就是数据结构的概念.数据结构 包括

数据结构与算法—线性表详解

前言 通过前面数据结构与算法前导我么知道了数据结构的一些概念和重要性,那么我们今天总结下线性表相关的内容.当然,我用自己的理解解分享给大家. 其实说实话,可能很多人依然分不清线性表,顺序表,和链表之间的区别和联系! 线性表:逻辑结构, 就是对外暴露数据之间的关系,不关心底层如何实现. 顺序表.链表:物理结构,他是实现一个结构实际物理地址上的结构.比如顺序表就是用数组实现.而链表用指针完成主要工作.不同的结构在不同的场景有不同的区别. 对于java来说,大家都知道List接口类型,这就是逻辑结构,

数据结构 笔记2 线性表

线性表是最简单,最常用的一种数据结构,它是由n个数据元素(结点)组成的有限序列. 线性表的基本运算 1.置空表 InitList(L) ,构造一个空的线性表L 2.求表长 ListLength(L) ,返回线性表L中元素个数,即表长. 3.取表中第i个元素GetNode(L,i) ,若1 <= i <= ListLength(L) ,则返回第i个元素a[i] 4.按值查找LocateNode(L,x),在表L中查找第一个值为x的元素,并返回该元素在表L中的位置,若表中没有元素的值为x,则返回0

数据结构一:线性表

线性表是最常用也是最简单的数据结构,几种常用的线性表的类模板C++描述描述如下: 1.顺序表 顺序表是将所有元素按逻辑顺序存储在一组地址连续的存储空间中的简单数据结构: 1 const int MAXSIZE = 1000; 2 template<class T> 3 class SeqList 4 { 5 public: 6 SeqList(){ lenght = 0; } // 无参构造函数 7 SeqList(const T a[], int n); // 带参构造函数,并用数组初始化