数据结构-表

    • 【知识索引】【数据结构(C语言)】
  • 一、线性表
    • (1)基本概念
      • 1.定义(性质相同的数据元素构成的有限序列)
      • 2.表长,空表,位序,直接前驱,直接后继
      • 3.基本操作(12)
    • (2)存储结构
      • 1.顺序表
      • 2.链表
  • 二、栈和队列
    • (1)栈
      • 1.基本概念
      • 2.存储结构
      • 3.栈的应用
    • (2)队列
      • 1.基本概念
      • 2.存储结构
  • 三、串
    • (1)基本概念及术语
      • 1.概念
      • 2.ADT
    • (2)基本操作
      • 1.最小操作子集
      • 2.其他操作
    • (3)串的表示方法
      • 1.顺序存储结构
      • 2.链式存储结构
    • (3)串的应用
      • 1.文本编辑
  • 四、数组和广义表
    • (1)数组
      • 1.数组的定义
      • 2.数组的顺序表示
      • 3.矩阵的压缩存储
    • (2)广义表
      • 1.定义
    • 文章索引

【知识索引】【数据结构(C语言)】




一、线性表

(1)基本概念

1.定义(性质相同的数据元素构成的有限序列)

2.表长,空表,位序,直接前驱,直接后继

3.基本操作(12)

InitList(&L); //构造一个空的线性表L ListEmpty(L);
//判断线性表L是否是空表,若是,则返回TRUE,否则返回FALSE ListLength(L); //返回线性表L的长度
GetElem(L,i,&e) ; //用e返回线性表L的第i个数据元素的值
LocateElem(L,e,compare());//在线性表L中查找第一个和元素e满足compare关系//的元素,若找到则返回其位序;否则返回0
PriorElem(L,e, &pre_e); //用pre_e返回线性表L中元素e的直接前驱 NextElem(L, e,
&next_e); //用next_e返回线性表L中元素e的直接后继 ListInsert(&L,i,e) ;
//将数据元素e插入到线性表L的第i个数据元素之前 ListDelete(&L,i,&e);
//删除线性表L的第i个数据元素,并将其值用e返回 ListTraverse(L,visit());
//依次对线性表L中的每个元素调用visit进行访问 ClearList(&L); //重置线性表L为空表
DestroyList(&L); //销毁线性表L,可能的话释放其空间

(2)存储结构

1.顺序表

用一组地址连续的存储单元依次存储线性表的数据元素。用顺序存储结构表示的线性表又称为顺序表。

  • 存储类型定义
  #define LIST_INIT_SIZE 100 //顺序表存储空间的初始分配量#define LISTINCREMENT 10  //顺序表存储空间的分配增量typedef struct{     ElemType *elem;  //存储空间的基地址int length;    //顺序表的当前长度int listsize;   //数组存储空间的长度}SqList;
  • 特点

    • 逻辑上相邻的数据元素在物理位置上也相邻
    • 随机存取
  • 基本操作

    • 初始化顺序表

      Status InitSqList(SqList& L) //顺序表初始化
      {L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));//申请初始分配空间
      if (L.elem == NULL) exit(OVERFLOW);//分配失败,返回OVERFLOW
      L.length = 0;//初始化表长为零
      L.listsize = LIST_INIT_SIZE;//初始化数组存储空间为初始分配空间
      return OK;//分配成功返回OK
      }
      
    • 销毁顺序表

      void DestroySqList(SqList& L)//销毁顺序表
      {if (L.elem != NULL)//如果顺序表存在free(L.elem);//释放存储空间
      L.elem = NULL;//存储空间基址置空
      }
      
    • 顺序表判空

      Status SqListEmpty(SqList L)//顺序表的判空操作
      {if (L.length == 0) return TRUE;//表长为零为空表
      else return FALSE;//表长非零不为空
      }
      
    • 顺序表求表长

      int SqListLength(SqList L)//顺序表求表长
      {return L.length;
      }
      
    • 获取元素

      Status GetSqElem(SqList L, int i, ElemType& e)//取第i个元素,用第三个参数e返回
      {if (i<1 || i>L.length)//判断索引是否有效return ERROR;//无效报错
      else
      {e = L.elem[i - 1];//有效则返回元素return OK;
      }
      }
      
    • 定位操作

      int SqLocateElem(SqList L, ElemType e)//定位元素e,返回元素位序,若元素不存在则返回零
      {int i;
      for (i = 1; i <= L.length; i++)//遍历数组
      {if (L.elem[i - 1] == e);//找到元素跳出循环break;
      }
      if (i <= L.length)//判断是否溢出return i;
      elsereturn 0;
      }
      
    • 插入操作

      Status SqListInsert(SqList& L, int i, ElemType e)//顺序表插入操作,在位序i上插入元素e
      {if (i<1 || i>L.length)//判断位序是否有效return ERROR;
      if (L.length == L.listsize)//判断是否溢出,如果溢出,重新分配空间
      {L.elem = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));if (!L.elem) exit(OVERFLOW);L.listsize += LISTINCREMENT;
      }
      ElemType* q;
      q = &L.elem[i - 1];
      for (ElemType* p = &L.elem[L.length - 1]; p >= q; p--)//从后向前移动元素
      {*(p + 1) = *p;
      }
      *q = e;
      L.length++;//更新表长
      return OK;
      }
      
    • 删除操作

      Status SqListDelete(SqList& L, int i)//删除顺序表第i个元素
      {if (i<1 || i>L.length) //判断参数是否溢出return ERROR;
      int j;
      for (j = i; j < L.length; j++)//从第i+1个元素开始到最后一个元素遍历
      {L.elem[j - 1] = L.elem[j];//每个元素向前移
      }
      L.length--;
      return OK;
      }
      
    • 遍历操作

      Status SqListTraverse(SqList L, Status(*visit)(ElemType))//顺序表遍历操作
      {int i;
      for (i = 0; i < L.length; i++)//循环遍历顺序表if (visit(L.elem[i])==FALSE) //遍历异常退出return ERROR;
      return OK;
      }
      定义比较函数:
      Status equal(ElemType a,ElemType b){if(a==b) return TRUE;else return FALSE;
      }
      
  • 优缺点

    • 优点:可以随机存取表中任一元素; 大部分操作都比较容易实现;存储利用率高(关系隐含在存储结构里,不需显式表示)
    • 缺点:不知道表的规模的情况下,2个常量的大小不太好确定;顺序表在进行插入和删除操作时,需要移动大量元素,浪费大量时间。
  • 顺序表应用

    • 把2个非递减有序的顺序表LA和LB归并为非递减有序的线性表LC

      void MergeList_Sq(SqList la,SqList lb,SqList &lc){//算法2.7
      pa=la.elem; pb=lb.elem;
      lc.listsize=lc.length=la.length+lb.length;
      pc=lc.elem = new ElemType[lc.listsize];
      pa_last=la.elem+la.length-1;  pb_last=lb.elem+lb.length-1;
      while(pa<=pa_last && pb<=pb_last) {if(*pa<=*pb) *pc++=*pa++;
      else *pc++=*pb++;
      }
      while(pa<=pa_last) *pc++=*pa++;
      while(pb<=pb_last) *pc++=*pb++;
      }
      
    • 顺序表的就地逆置

      void reverse1(Sqlist &A)
      {for(i=0,j=A.length-1;i<j;i++,j--)A.elem[i]<->A.elem[j];
      }//reverse1
      

2.链表

用一组任意的存储单元(可连续可不连续)存储线性表中的数据元素。

  • 单链表

    线性单链表:n个结点(每个结点只包含一个指针域)链接而成的链表。

    • 存储类型定义

      typedef struct LNode {ElemType data;    //数据域
      struct LNode* next; //指针域
      }LNode, * LinkList;
      
    • 特点

      • 任何两个元素的存储位置没有固定的联系
      • 每个元素的存储位置只能由其直接前驱结点的指针指出
      • 链表是顺序存取的存储结构
    • 特殊节点

      • 头结点
      • 首元结点
      • 尾元结点
    • 基本操作

      • 初始化单链表链表

        Status InitLinkList(LinkList& L) //初始化链表
        {L = (LinkList)malloc(sizeof(LNode));//申请头节点
        if (L == NULL) exit(OVERFLOW);//申请失败返回异常
        L->next = NULL;//头节点置空
        return OK;
        }
        
      • 单链表的判空操作

        Status LinkListEmpty(LinkList L) //单链表的判空操作
        {if (L->next == NULL)//判断头指针是否为空return TRUE;
        else return FALSE;
        }
        
      • 销毁单链表

        void DestroyLinkList(LinkList& L) //销毁单链表
        {LinkList p;//新建节点指针
        while (L != NULL)//头指针非空
        {p = L->next;//p指针保留将要释放的节点指针域free(L);//释放节点L = p;//更新头节点
        }
        }
        
      • 单链表求表长

        int LinkListLength(LinkList L) //单链表求表长操作
        {LinkList p;
        int n = 0;
        for (p = L->next; p != NULL; p = p->next, n++);//从首元节点遍历单链表并计数
        return n;
        }
        
      • 清空单链表

        void ClearLinkList(LinkList L) //清空单链表
        {LinkList p;
        for (p = L->next; p != NULL; p = L->next)//从首元节点遍历释放节点空间
        {L->next = p->next;//更新头节点指针free(p);//释放首元节点
        }
        }
        
      • 单链表取值

        Status GetLinkElem(LinkList L, int i, ElemType& e) //单链表取第i个值,由e返回
        {int count;//计数变量
        LinkList p = L;//遍历指针初始为头指针
        for (count = 0; count < i && p != NULL; count++)//计数器置零,遍历到第i个,指针为空异常退出
        {p = p->next;
        }
        if (i > count)//判断是否异常退出return ERROR;
        else//正常退出返回OK
        {e = p->data;return OK;
        }
        }
        
      • 单链表定位

        LinkList LinkLocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType))
        //单链表定位操作,返回第一个满足关系的节点指针,若无满足关系的元素,返回空指针
        {LinkList p = L->next;//从首元节点遍历链表
        while (p!=NULL && compare(p->data, e)==FALSE) //直到满足关系或遍历结束停止遍历p = p->next;
        return p;//返回指针
        }
        
      • 单链表插入操作

        Status LinkListInsert(LinkList& L, int i, ElemType e)//单链表插入操作
        {int count;//计数变量
        LinkList p;//循环指针
        for (count = 0, p = L; count < i - 1 && p != NULL; p = p->next, count++);//定位第i-1个节点
        if (i < 0 || count < i - 1) //判断i取值是否合理return ERROR;
        else
        {LinkList q;q = (LinkList)malloc(sizeof(LNode));//创建待插入节点空间q->data = e;q->next = p->next;//插入节点指向其后继p->next = q;//连接其前驱节点
        }
        return OK;
        }
        
      • 单链表删除操作

        Status LinkListDelete(LinkList& L, int i)
        {int count;//计数变量
        LinkList p;//循环指针
        for (count = 0, p = L; count < i - 1 && p != NULL; p = p->next, count++);//定位第i-1个节点
        if (i < 0 || count < i - 1) //判断i取值是否合理return ERROR;
        else
        {LinkList q = p->next;//指向待删除节点p->next = q->next;//前驱节点指针域更新free(q);//删除节点
        }
        return OK;
        }
        
      • 遍历单链表

        Status LinkListTraverse(LinkList L,Status(*visit)(ElemType)) //遍历单链表
        {LinkList p;
        for (p = L->next; p; p = p->next)if (!visit(p->data)) return ERROR;
        return OK;
        }
        
    • 应用

      • 逆向建立n个元素的单链表

        void CreateList_backward(LinkList &L,int n)
        { //逆向建立n个元素的单链表
        L=( LinkList) malloc(sizeof(LNode));
        L->next=NULL;
        for(i=0; i<n; i++)
        { p=( LinkList) malloc(sizeof(LNode));scanf(&p->data);  p->next=L->next; L->next=p;
        }//for
        }// CreateList_backward
        
    • 优缺点

      • 优点:链表在进行插入和删除操作时,不再移动大量元素,仅需修改指针;不再需要定义2个常量
      • 缺点:元素只能顺序存取;大部分操作的时间复杂度都为O(n);存储利用率较低(存储元素时要附带存储指针)
  • 循环链表

    • 优点:从表中任一结点出发都可找到表中其他结点。

    • 操作

      和线性链表基本一致,差别在于判空和判表尾条件

      • 判空: L->next==L

      • 表尾:p->next==L

      • 在带头结点的循环链表中设置尾指针可方便某些操作

        • 查找尾元结点
        • 查找首元结点
    • 应用

      • 两个循环链表合并

        仅设尾指针的循环链表
        p=LA->next;
        LA->next=LB->next->next;
        free(LB->next);
        LB->next=p;
        LA=LB;

  • 双向链表

    • 双向链表C语言描述

      typedef struct DulNode{ElemType data;
      Struct DulNode *prior;//指向其直接前驱的指针域
      Struct DulNode *next; //指向其直接后继的指针域
      }DulNode,*DuLinkList;
      
    • 操作

      某些操作算法与线性单链表的操作相同;
      插入、删除等操作需同时修改两个方向的指针

      • 插入

        Status ListInsert_Dul(DuLinklist &L,int i,ElemType e)
        {if(!(p=GetElem_DuL(L,i)))
        return ERROR;
        if(!(s=(DuLinkList)malloc(sizeof(DuLNode))))
        return ERROR;
        s->data=e;
        ① s->prior=p->prior;
        ② p->prior->next=s;
        ③ s->next=p;
        ④ p->prior=s;
        return OK;
        }
        
      • 删除

        Status ListDelete_Dul(DuLinklist &L,int i,ElemType &e)
        {if(!(p=GetElem_DuL(L,i)))
        return ERROR;
        e=p->data;
        ① p->prior->next=p->next ;
        ② p->next->prior=p->prior;
        ③ free(p);
        return OK;
        }
        

二、栈和队列

(1)栈

1.基本概念

栈:限制仅在表的一端进行插入和删除的线性表

  • ADT定义

    ADT Stack { 数据对象:D={ai| ai  ElemSet, i=1,2,…,n, n0} 数据关系:R={<
    ai-1, ai >| ai-1,ai D,i=2,…,n}
    约定an端为栈顶, a1端为栈底 基本操作:InitStack(&S); StackEmpty(S);
    StackLength(&S); GetTop(S, &e);
    Push(&S, e); Pop(&S, &e);
    ClearStack(&S);
    StackTraverse(S, visit());
    DestroyStack(&S); } ADT Stack

  • 栈顶:允许插入、删除的一端。

  • 栈底:与栈顶相对的另一端。

  • 空栈:表中没有元素的栈

2.存储结构

  • 顺序栈

    特点:用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素
    栈中元素可动态增删,即栈长是可变的,因此和顺序表一样,用动态分配的一维数组来表示顺序栈

    • 存储结构的定义

      #define STACK_INIT_SIZE 100 //顺序栈存储空间的初始分配量
      #define STACKINCREMENT 10  //顺序栈存储空间的分配增量typedef struct
      {SElemType* base; //栈底指针,始终指示存储空间的基址
      SElemType* top; //栈顶指针,指向栈顶元素的下一个位置
      int stacksize;  //数组存储空间的长度
      }SqStack;//顺序栈定义
      
      • 栈底指针,始终指示存储空间的基址
      • 栈顶指针,指向栈顶元素的下一个位置
      • 数组存储空间的长度
    • 基本操作

      • 构造空栈

        Status InitSqStack(SqStack& S)
        {
        S.base = (SElemType*)malloc((STACK_INIT_SIZE) * sizeof(SElemType));// 栈的连续空间分配
        if (!S.base)
        {exit(OVERFLOW);
        }
        S.top = S.base; //空栈,初始化栈顶指针
        S.stacksize = STACK_INIT_SIZE;
        return OK;
        }//构造一个空栈,该栈由指针S指示
        
      • 销毁栈

        Status DestroySqStack(SqStack& S)
        {if (S.base) //栈底指针非空free(S.base);
        S.base = NULL;
        return OK;
        }//销毁栈
        
      • 清空栈

        Status ClearSqStack(SqStack& S)
        {S.top = S.base;
        return OK;
        }//清除栈
        
      • 判空

        Status SqStackEmpty(SqStack S)
        {return S.top == S.base;
        }//栈的判空操作
        
      • 求栈长

        int SqStackLength(SqStack S)
        {return S.top - S.base;
        }//求栈长
        
      • 取栈顶元素

        Status GetTopSq(SqStack S, SElemType& e)
        {if (S.top == S.base) return ERROR;
        e = *(S.top - 1);
        return OK;
        } //用指针e带回栈顶元素
        
      • 入栈

        Status SqPush(SqStack& S, SElemType e)
        {//入栈,插入元素e为新的栈顶元素
        if (S.top - S.base == S.stacksize)//栈满
        {S.base = (SElemType*)realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(SElemType));if (!S.base) exit(OVERFLOW);S.top = S.base + S.stacksize;S.stacksize += STACKINCREMENT;
        }//重新分配更大的连续空间
        *S.top++ = e;
        return OK;
        }//Push
        
      • 出栈

        Status SqPop(SqStack& S, SElemType& e)
        {if (S.top == S.base) //栈空return ERROR;
        --S.top;
        e = *S.top;
        return OK;
        }//出栈,删除的栈顶元素用指针e指示
        
      • 遍历

        Status SqStackTraverse(SqStack S, Status(*visit)(SElemType))
        {//从栈底到栈顶依次对栈S中的每个数据元素调用visit
        //指向的函数进行访问
        SElemType* p;
        for (p = S.base; p < S.top; p++)if (!visit(*p)) return ERROR;
        return OK;
        }// 栈的遍历
        
  • 链栈

    • 链栈类型定义

      typedef struct SNode{SElemType data;   //数据域
      struct SNode *next; //指针域
      }SNode,*LinkStack;
      
      • 由于栈顶的位置特殊,所以链栈的头指针指向栈顶元素所在结点
      • 注意:不必设头结点
    • 基本操作

      • 链栈入栈

        Status Push(LinkStack &S, SElemType e)
        {//插入e到栈S中使之成为新的栈顶元素
        p=( LinkStack)malloc(sizeof(SNode));
        if(!p) exit(OVERFLOW);
        p->data=e;
        p->next=S;
        S=p;
        return OK;
        }//Push
        
      • 链栈出栈

        Status Pop(LinkStack &S, SElemType &e)
        {//若栈不空则出栈,删除的栈顶元素用e指示
        if(!S) return ERROR; //栈空
        p=S;
        S=S->next;
        e=p->data;
        free(p);
        return OK;
        }//Pop
        

3.栈的应用

  • 数制转换

  • 括号匹配的检验

  • 迷宫求解

    Typedef struct { //栈的元素类型定义int ord; //通道块在路径上的“序号”PosTpye seat ; //通道块在迷宫中的“坐标位置”int di;  //从此通道块走向下一通道块的“方向”
    }SElemType;  Status MazePath(MazeType maze, PosType start, PosType end){InitStack(s); curpos=start; //设定当前位置为入口位置curstep =1;do{ if(Pass(curpos)) { //当前位置可通FootPrint(curpos);  //留下足迹e=(curstep, curpos, 1);push(s,e);      //加入路径if(curpos==end) return(TRUE); //到达终点curpos= NextPos(curpos, 1); //下一位置是当前位置的东邻curstep++;  //探索下一步}//ifelse { //当前位置不能通过if (!StackEmpty(S)) {
    Pop(S,e);
    while(e.di==4 && !StackEmpty(s)){MarkPrint(e.seat); Pop(s,e);
    //留下不能//通过的标记,并退回一步
    }//while
    if (e.di<4){e.di++; Push(S,e); //换下一方向搜索curpos=NextPos(e.seat, e.di);//设定当前位置是该新方向上的相邻块
    }//if
    }//if
    }//else
    } while(!StackEmpty(S));
    return(FALSE);
    }// MazePath
    
  • 算术表达式求值

    OperandType EvaluateExpression(){InitStack(OPTR); Push(OPTR, '#');
    InitStack(OPND); c=getchar();
    while(c!= '#' || GetTop(OPTR)!= '#'){if (!In(c,OP)) {Push(OPND,c); c=getchar();}
    else switch(Precede(GetTop(OPTR),c)){case '<': Push(OPTR,c); c=getchar(); break;case '=': Pop(OPTR,x); c=getchar(); break; case '>': Pop(OPTR,theta); Pop(OPND,b); Pop(OPND,a);Push(OPND,Operate(a,theta,b)); break; }//switch
    }//while
    return GetTop(OPND);
    }// EvaluateExpression
    
  • 栈与递归

(2)队列

1.基本概念

队列:只允许在表的一端进行插入,而在另一端进行删除的线性表。

  • ADT

    ADT Queue {
    数据对象:D={ai | ai  ElemSet, i=1,2,…,n, n>=0}
    数据关系:R={< ai-1, ai > | ai-1, ai D, i=2,3,…,n}
    约定a1端为队头,an端为队尾
    基本操作:InitQueue(&Q); QueueEmpty(Q);
    QueueLength(Q); GetHead(Q, &e);
    EnQueue(&Q, e); DeQueue(&Q, &e);
    ClearQueue(&Q);
    QueueTraverse(Q, Visit());
    DestroyQueue(&Q); }ADT Queue

  • 队头:允许删除的一端

  • 队尾:允许插入的一端

  • 空队列:没有元素的队列

  • 双端队列:限定插入和删除操作在表两端进行的线性表

  • 输出受限队列:一端允许插入和删除,另一端只允许插入。

  • 输入受限队列:一端允许插入和删除,另一端只允许删除。

2.存储结构

  • 链队列

    使用二个指针分别记录队头和队尾的当前位置
    设立一个头结点,并令头指针指向头结点,头结点的指针域指向队头元素所在的结点
    链队列的判空条件:头指针和尾指针均指向头结点

    • 链队列类型定义

      typedef struct QNode{QElemType data;
      struct QNode *next;
      }QNode,*QueuePtr;
      typedef struct {QueuePtr front; //头指针
      QueuePtr rear;  //尾指针
      }LinkQueue;```
    • 基本操作

      • 链队列入队

        Status EnQueue(LinkQueue &Q, ElemType e)
        {
        p=(QueuePtr)malloc(sizeof(QNode));
        if(!p) exit(OVERFLOW);
        p->data=e; p->next=NULL;
        Q.rear->next=p;
        Q.rear=p;  //尾指针指向新的尾结点
        return OK;
        }// EnQueue
        
      • 链队列入出队

        Status DeQueue(LinkQueue &Q, ElemType &e)
        {if(Q.rear == Q.front) return ERROR;
        p=Q.front->next;
        e=p->data;
        Q.front->next=p->next;
        if(Q.rear==p) Q.rear=Q.front;
        //若队头元素是队列中唯一的一个元素, 则删除该结点后//还需要修改尾指针,让它指向头结点
        free(p);
        return OK;
        } // DeQueue
        
  • 顺序队列

    • 普通顺序队列

      用一组地址连续的存储单元依次存储从队头到队尾的数据元素。

      • 顺序队列类型定义

        #define MAXQSIZE 100
        typedef struct {QElemType *base; //存储空间基地址
        int front;//队头指针,指向队头元素
        int rear;//队尾指针,指向队尾元素的下一个位置
        }SqQueue;
        
      • 假上溢现象

    • 循环队列

      • 存储结构定义

        • 少用一个元素空间,约定队列头指针在队尾指针下一个位置为队列满

          #define MAXQSIZE 100
          typedef int QElemType;
          typedef struct {QElemType* base; //存储空间基地址
          int front;//队头指针,指向队头元素
          int rear;//队尾指针,指向队尾元素的下一个位置
          }SqQueue;
          
        • 另设标志位区别队列空、满

          typedef struct {ElemType *base;
          int front;
          int rear;
          int tag;
          }SqQueue;
          
      • 基本操作

        • 初始化队列

          Status InitSqQueue(SqQueue& Q)//初始化队列
          {Q.base = (QElemType*)malloc(MAXQSIZE * sizeof(QElemType));
          if (Q.base == NULL)exit(OVERFLOW);
          Q.front = Q.rear = 0;//队头队尾指针都指向0
          return OK;
          }
          
        • 求队长

          int SqQueueLength(SqQueue Q)//求队长
          {return(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
          }
          
        • 进队

          Status EnSqQueue(SqQueue& Q, QElemType e)//进队操作
          {if ((Q.rear + 1) % MAXQSIZE == Q.front) //队列满的判定条件(防止队满和队空无法区分,留下一个位置不用return ERROR; //队满直接报错,不再申请更大的内存
          else
          {Q.base[Q.rear] = e;Q.rear = (Q.rear + 1) % MAXQSIZE;//队尾指针后移,%MAXQSIZE使下标首尾相接return OK;
          }
          }
          
        • 出队

          Status DeQueue(SqQueue& Q, QElemType& e)//出队操作
          {if (Q.front == Q.rear) //队空的判定条件return ERROR; //队空报错
          else
          {e = Q.base[Q.front];Q.front = (Q.front + 1) % MAXQSIZE;return OK;
          }
          }
          
        • 判空

          Status SqQueueEmpty(SqQueue Q)//循环队列的判空操作
          {if (Q.rear == Q.front)return TRUE;
          elsereturn FALSE;
          }
          
        • 取队头元素

          Status GetSqHead(SqQueue Q, QElemType& e)//取队头元素
          {if (Q.rear == Q.front)return ERROR;
          else
          {e = Q.base[Q.front];return TRUE;
          }
          }
          
        • 清空队列

          Status ClearSqQueue(SqQueue& Q)//清空队列
          {Q.rear = Q.front;
          return OK;
          }
          
        • 销毁队列

          Status DestroySqQueue(SqQueue& Q)//销毁队列
          {free(Q.base);
          Q.front = Q.rear = 0;
          return OK;
          }
          
        • 队列的遍历

          Status SqQueueTraverse(SqQueue Q, Status (*visit)(QElemType))
          {
          int i;
          for (i = Q.front; i != Q.rear; i = (i + 1) % MAXQSIZE)
          {visit(Q.base[i]);}
          return OK;
          }
          

三、串

(1)基本概念及术语

1.概念

  • 串:

    由零个或多个字符组成的有限序列。记为:s= ‘a1 a2…an’ (n>=0)

  • 串名: s

  • 串值: a1a2a3……an

  • 串长: n

  • 空串:串长为0的串。用Φ表示

  • 子串:串中任意个连续的字符组成的子序列

    • 串是其自身的子串
    • 空串是任意串的子串
  • 主串:包含子串的串

  • 字符在串中的位置:字符在串中的序号

  • 子串在主串中的位置:子串的第1个字符在主串中的位置

  • 空格串:由一个或多个空格组成的串,其长度为空格个数

  • 串相等:两个串长度相等且各个对应位置的字符也相等

2.ADT

ADT String { 数据对象:D={ai| ai CharacterSet, i=1,2,…,n, n0}
数据关系:R1={< ai-1 ,ai >| ai-1 , ai  D,i=2,3,…,n} 基本操作:
StrAssign(&T, chars); StrCopy(&T,S);
StrEmpty(S); StrCompare(S,T);
StrLength(S); ClearString(&S);
Concat(&T,S1,S2); Substring(&Sub, S, pos,len);
Index(S,T,pos); Replace(&S,T,V);
StrInsert(&S, pos, T); StrDelete(&S, pos, len);
DestroyString(&S); }ADT String;

(2)基本操作

1.最小操作子集

  • 串赋值StrAssign
  • 串比较StrCompare
  • 求串长StrLength
  • 串联接Concat
  • 求子串SubString

2.其他操作

  • 串拷贝StrCopy
  • 串判空StrEmpty
  • 定位串Index
  • 串替换Replace
  • 串插入StrInsert
  • 串删除StrDelete
  • 串清空ClearString
  • 销毁串DestroyStr

(3)串的表示方法

1.顺序存储结构

  • 定长存储结构

    • 特点:用长度固定的连续单元依次存储串值的字符序列
    • 以下标为0的数组分量存放实际串长——PASCAL
    • 串值后加一个不计入串长的结束标记字符——C、C++中用‘\0’作串的结束标记
  • 堆分配存储结构

    • 特点:采用动态字符数组存放串值,此时不必为数组预定义大小,以串长动态分配数组空间

    • 数据类型定义

      typedef struct {char *ch;
      int length;
      }HString;
      

2.链式存储结构

  • 块链结构

    • 数据类型定义

      #define CHUNKSIZE 80 // 可由用户定义的块大小
      typedef struct Chunk { // 结点结构
      char ch[CUNKSIZE];
      struct Chunk *next;
      } Chunk;
      typedef struct { // 串的链表结构Chunk *head, *tail; //串的头和尾指针,便于联结操作int  curlen;      // 串的当前长度
      } LString;
      

(3)串的应用

1.文本编辑

  • 实质:修改字符数据的形式或格式
  • 基本操作:输入、查找、修改、删除、输出

四、数组和广义表

(1)数组

1.数组的定义

  • ADT

    ADT Array { 数据对象:ji=0, …, bi – 1, i = 1, 2, …, n,
    D={ | ∈ElemSet } 数据关系:R = {R1, R2, …, Rn}
    Ri={ |0 ≤ jk ≤ bk–1, 1 ≤ k ≤n且
    k!=i, 0 ≤ ji ≤ bi–2, ∈D, i=1,2,…,n} 基本操作: InitArray(&A, n, bound1, …, boundn) DestroyArray(&A)
    Value(A, &e, index1, …, indexn) Assign(&A, e, index1, …, indexn)
    }ADT Array

  • n维数组是线性表的扩展

    • 当n=1,n维数组退化成顺序表
    • 当n>1,n维数组可看成表中数据元素是n-1维数组的线性表

2.数组的顺序表示

因为数组一般不做插入/删除操作,所以用顺序结构表示数组是很自然的。

  • 特点:用一组地址连续的存储单元按照某种规则存放数组中的数据元素。

  • 2种顺序(顺序存储方式)

    • 以行序为主(低下标优先法)
    • 以列序为主(高下标优先法)
  • 元素地址的计算

    • 要素

      • ①数组的起始地址(即基地址)
      • ②数组维数和各维的长度;
      • ③数组中每个元素所占的存储单元
    • 计算方法

      • 二维

        • 行主序:LOC(i,j) = LOC(0,0) + ( b2*i + j ) * L

        • 列主序:LOC(i,j) = LOC(0,0) + ( b1*j + i ) * L

        • 二维数组元素地址的通式

          • 行优先存储时的地址公式为:

            • LOC(aij)=LOC(ac1,c2)+[(i-c1)*(d2-c2+1)+j-c2)]*L
          • 列优先存储的通式为:

            • LOC(aij)=LOC(ac1,c2)+[(j-c2)*(d1-c1+1)+i-c1)]*L
      • 多维

        • 设各维长度分别为b1, b2, b3, …, bn,每个元素占L个存储单元, 起始地址是LOC(0,0,…,0)
        • LOC (j1,j2,…,jn ) = LOC(0,0,…,0) + (b2b3bn * j1+ b3b4*…bn * j2+ ……+ bnjn-1 + jn ) * L
    • 随机存储结构

      数组元素的存储位置是其下标的线性函数,由于计算各个元素存储位置的时间相等,所以存储数组中任一元素的时间也相等,具有这一特点的存储结构为随机存储结构。

  • 实现

    #define MAX_ARRAY_DIM 8
    typedef struct {ElemType    *base;      //存储空间基址
    int dim;              //数组维数
    int *bounds;        //数组维界基址
    int *constants;       //数组映象函数常量{Ci}基址
    } Array;
    

3.矩阵的压缩存储

压缩存储:为多个值相同的元素只分配一个存储空间,对零元素不分配空间。

  • 特殊矩阵:值相同的元素或零元素在矩阵中分布有一定规律。如三角矩阵、对角矩阵。

    • 对称矩阵

      n阶矩阵A中元素满足性质a[i][j]=a[j][i] (1 ≤i, j≤ n)

      • 压缩存储

        为每一对对称元素分配 个存储空间. n2 n(n+1)/2
        用行主序的下(上)三角阵来存储对称矩阵的元素。
        sa[k](0 ≤ k ≤ n(n+1)/2-1) 为对称矩阵的压缩存储结构

    • 上(下)三角阵

      下(上)三角(不含对角线)元素为常数c或0的n阶矩阵

      • 压缩存储

        存储上(下)三角中的元素和常数c
        用行主序存储上(下)三角阵的元素
        sak 为上(下)三角阵的压缩存储结构

    • 对角矩阵

      所有非零元素都集中在以主对角线为中心的带状区域。其他元素为0。

      • 压缩存储

        用行主序存储带状区域的非0元素

  • 稀疏矩阵:值相同的元素或零元素在矩阵中分布没有一定规律。

    • 稀疏因子

      设m行n列的矩阵含t个非零元素,定义δ=t/(m*n)为稀疏因子,则  0.05 的矩阵为稀疏矩阵。

    • 稀疏矩阵的压缩存储

    • 表示

      • 三元组( i,j,aij )

        • 三元组的C语言描述

          typedef struct {int i,j;ElemType e;
          }Triple;
          
        • 三元组顺序表的C语言描述

          #define MAXSIZE 1250
          typedef struct{Triple data[MAXSIZE+1]; //data[0]未用int mu,nu,tu;
          }TSMatrix;
          
      • 行逻辑链接的顺序表

        需求:随机存取任意一行的非0元
        方法:记住矩阵每一行第一个非0元在三元组顺序表中的位置
        设数组rpos[1…n]:矩阵中每行第一个非零元素的起始位置
        rpos[1]=1;
        rpos[row]=rpos[row-1]+第row-1行的非零元素个数
        第i行所有非0元在data中的位置:rpos[i]…rpos[i+1]-1
        行逻辑链接顺序表:在稀疏矩阵的三元组顺序表中设置指示行信息的辅助数组rpos
        typedef struct{
        Triple data[MAXSIZE+1];
        int rpos[MAXRC+1];//各行第1个非零元位置表,rpos[0]未用
        int mu,nu,tu;
        }RLSMatrix;

      • 十字链表

    • 转置

      • 稀疏矩阵转置方法一

        Status TransposeSMatrix(TSMatrix M,TSMatrix &T)
        {  T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;if(T.tu){  q=1;for(col=1;col<=M.nu;++col)for(p=1;p<=M.tu;++p)if(M.data[p].j==col){T.data[q]=(M.data[p].j, M.data[p].i, M.data[p].e); ++q;}
        } return OK;
        }//TransposeSMatrix
        
      • 稀疏矩阵转置方法二

        Status FastTransposeSMatrix(TSMatrix M,TSMatrix &T)
        { T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;
        if(T.tu)
        { for(col=1;col<=M.nu;++col) num[col]=0;for(t=1;t<=M.tu;++t) ++num[M.data[t].j];cpot[1]=1;for(col=2;col<=M.nu;++col) cpot[col]=cpot[col-1]+num[col-1];for(p=1;p<=M.tu;++p) {col=M.data[p].j; q=cpot[col];T.data[q]=( M.data[p].j, M.data[p].i, M.data[p].e );  ++cpot[col];    }//for
        }//if
        return OK;
        }//FastTransposeSMatrix
        

(2)广义表

1.定义

广义表(列表):n (0)个元素组成的有限序列,记作
LS = (α1, α2, …, αn) 其中αi 可以是单个元素(原子),也可以是广义表(子表)

  • 表头(head):n>0时,广义表的第一个元素
  • 表尾(tail):除第一个元素外的所有其它元素组成的表
  • 空表:n = 0 的广义表
  • 广义表长度:广义表中元素的个数
  • 广义表深度:广义表中括号的重数

文章索引

  • 【知识索引】【数据结构(C语言)】
  • 【数据结构(C语言)】数据结构-表
  • 【数据结构(C语言)】数据结构-树
  • 【数据结构(C语言)】数据结构-图
  • 【数据结构(C语言)】数据结构-查找
  • 【数据结构(C语言)】数据结构-内部排序

【数据结构(C语言)】数据结构-表相关推荐

  1. c语言 静态链表插入排序,数据结构C语言版 表插入排序

    西门豹治邺奇计 数据结构C语言版 表插入排序.txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了.他只是比对方更珍惜这份感情./* 数据结构C语言版 表插入排序 算法10.3 P267-P2 ...

  2. 数据结构C语言——广义表

    很久没有发博客记录了,不过应该也没人关心这个,哈哈哈. 突然想起来,学习也不能只是干学,稍微做点记录. 之前我对html.css.js基础有了一定的理解,也学了一些模板,不过现在我想先把计算机基础给补 ...

  3. c语言编程文件中删除数据结构,C语言数据结构实战(一)顺序表的插入与删除

    今天学习了思成老师的数据结构实战教程 写了一个顺序表 插入和删除的操作 把源码共享给大家 一共包括list.c stu.h main.c list.h   .h文件是头文件 需要引入 具体的功能我都已 ...

  4. 数据结构(C语言)顺序表的定义及基本操作

    顺序表的定义及基本操作 一.数据结构:顺序表的定义,创建,基本运算,实现 二.全部代码 定义顺序表 #include<stdio.h> #include<malloc.h> # ...

  5. 数据结构C语言顺序表入门简单题目你会了吗?

    通常,线性表可以采取顺序存储和链式存储两种,今天我们来讨论下顺序存储结构以及其对应的实现算法. 采用顺序存储是表示线性表的最简单的方法,具体做法是:将线性表中的元素一个接一个地存储在一片相邻的存储区域 ...

  6. 栈的应用行编辑数据结构c语言,数据结构题典022:栈的应用——行编辑程序(C语言版)...

    编写程序实现从终端接收用户输入的数据,并存入用户数据区.输入#表示上一字符无效,输入@表示当前输入行整行无效. /* * line editor by using stack. * * fduan, ...

  7. c语言数据结构线性表LA和LB,数据结构(C语言版)设有线性表LA(3,5,8,110)和LB(2,6,8,9,11,15,20)求新集合?...

    数据结构(C语言版)设有线性表LA(3,5,8,110)和LB(2,6,8,9,11,15,20)求新集合? 数据结构(C语言版)设有线性表LA(3,5,8,110)和LB(2,6,8,9,11,15 ...

  8. 逆置单链表c语言程序,(数据结构C语言版)顺序表和单链表的逆置

    <(数据结构C语言版)顺序表和单链表的逆置>由会员分享,可在线阅读,更多相关<(数据结构C语言版)顺序表和单链表的逆置(7页珍藏版)>请在人人文库网上搜索. 1.实验1-1顺序 ...

  9. 数据结构——无向图创建邻接表以及深度遍历、广度遍历(C语言版)

    摘自:数据结构--无向图创建邻接表以及深度遍历.广度遍历(C语言版) 作者:正弦定理 发布时间:2020-12-22 20:55:12 网址:https://blog.csdn.net/chinese ...

  10. 顺序表输入栈元素c语言,C语言数据结构之栈简单操作

    C语言数据结构之栈简单操作 实验: 编写一个程序实现顺序栈的各种基本运算,并在此基础上设计一个主程序,完成如下功能: (1)初始化顺序栈 (2)插入元素 (3)删除栈顶元素 (4)取栈顶元素 (5)遍 ...

最新文章

  1. redis一:非关系型数据库
  2. 设计模式(二)————观察者模式
  3. .Net Validator验证框架 [ .Net | Validator Framework | Attribute ]
  4. Windows Server 2016与旧版本系统比较
  5. shell获取执行脚本路径
  6. Linux运维-day3
  7. chrome本地文件加载跨域请求
  8. 利用React/anu编写一个弹出层
  9. Cesium:在地球上加载Geoserver图层
  10. 为什么要Code Review
  11. Android Retrofit 2.0 使用-补充篇
  12. pythonpdf使用教程_Python基础学习教程:Python玩转PDF各种骚操作大全
  13. 开运算和闭运算的性质
  14. matlab矩阵排序sort,MATLAB数组元素的排序
  15. java生成随机数组_Java 生成随机数
  16. 全国大学生大数据技能竞赛比赛心得以及相关资料
  17. H5+js实现别踩白块儿
  18. oracle general ledger,处理 Oracle General Ledger 调整期间
  19. iOS 设备的屏幕尺寸、分辨率及其屏幕边长比例详细情况
  20. excel表格如何换行

热门文章

  1. C++之unique_ptr
  2. kalilinux装到u盘上的弊端_你有一个 U 盘制作多系统安装盘的需求吗,YUMI 帮你秒实现!...
  3. php简单选择题,念做个简易php选择题答题系统
  4. ubuntu18.04安装mysql8.0
  5. php ext在哪里,PHP Ext API
  6. python二维列表转字典_在Python中字符串、列表、元组、字典之间的相互转换
  7. 此流上不支持超时。_10分钟了解线程池,阿里再也不担心我线程池资源耗尽了...
  8. python列表的排序方法是_Python列表排序 reverse、sort、sorted 操作方法详解
  9. 低解密指数攻击_CTF中RSA的一些攻击思路
  10. java序列化和反序列化对象_java中的序列化与反序列化,还包括将多个对象序列化到一个文件中...