软考复习:数据结构基础(1.1线性表)

来源:互联网 发布:关于考研的淘宝店铺 编辑:程序博客网 时间:2024/05/20 06:51

1.1 线性表

线性表的基本运算

1. 查找运算
在线性表中查找具有给定键值的结点
2. 插入运算
在线性表第i(0<=i<=n-1)个结点的前面或者后面插入一个新的结点
3. 删除运算
删除线性表的第i(0<=i<=n-1)个结点。
4. 其他运算
- 统计线性表中节点的个数
- 输出线性表各节点的值
- 复制线性表
- 线性表分拆
- 线性表合并
- 线性表排序
- 按某种规则整理线性表

线性表的存储

  1. 顺序存储
    顺序存储通常用一个数组。
    优点:能随机存取线性表中的任何一个结点
    缺点:1,数组大小通常是固定的,不利于任意增加或减少线性表节点的个数
    2,插入和删除线性表的结点时,要移动数组中的其他元素,操作复杂

  2. 链式存储
    链式存储是用链表存储线性表
    优点:每个结点的实际存储位置是任意的,插入和删除操作方便,不需要移动表元
    缺点:1,每个节点增加了一个后继指针成分,增加了存储空间
       2,不便随机访问线性表的任一结点

在线性表中插入新结点

  1. 顺序存储

设线性表结点类型为整形,插入之前有n个结点,把值为x的结点插入线性表的第i个位置上

插入步骤为:
1. 检查插入要求的有关参数的合理性
2. 把原来的第n个结点到第i个结点依次往后移动一个数组元素位置
3. 把新结点放在第i个位置上
4. 修正线性表的结点个数

  1. 链式存储

在廉洁存储线性表中插入一个键值为x的新结点,分为如下4种情况

  • 在某指针p所指结点之后插入
  • 插在首结点之前,使待插入结点成为新的首结点
  • 接在线性表的末尾
  • 在有序链表中插入,使新的线性表任然有序

删除线性表的结点

  1. 顺序存储

删除步骤:
1. 检查删除要求的有关参数的合理性
2. 把原来第i+1个表元至第n个结点依次向前移动一个数组元素位置
3. 修正线性表结点个数

  1. 链式存储

删除步骤:
1. 如链表为空链表,则不执行删除操作
2. 如链表的首结点的值为指定值,更改表的头指针为指向首结点的后继结点
3. 在链表中寻找指定值的结点
4. 将找到的结点删除

1.1.1 栈

  1. 顺序存储
    可以用顺序存储线性表来表示栈,为了指明当前执行插入和删除运算的栈顶位置,需要一个地址变量top
    指出栈顶结点在数组中的下标

  2. 链式存储
    可以用链表实现。

1.1.2 队列

具有先进先出的特征

  1. 顺序存储
    随着一系列进队和出队运算,会出现前端空着,而队列空间已用完的情况
    一种可行的方法是把队列中的结点一刀队列的前端,修改头指针和尾指针
    另一种更好的解决方法是采用循环队列

    循环队列就是将队列数组的第一个元素与最后一个元素连接起来。
    由于其中会造成队空和队满的条件同为head==tail。因此可采用只剩下一个空闲结点,就认为队列已满

  2. 链式存储

1.1.3 稀疏矩阵

如果一个矩阵的元素绝大部分都为零,则称为稀疏矩阵。若直接用一个二维数组表示稀疏矩阵会浪费大量的
内存空间,通常采用三元组数组或者十字链表两种方法来表示稀疏矩阵

  1. 三元组数组

    稀疏矩阵中的每个非零元素都用一个三元组来表示,即非零元素的 行号,列号,和他的值
    然后按照某种顺序将全部非零元素的三元组存入一个数组中

如果只对稀疏矩阵的某些单个元素进行处理,则宜采用三元组表示

相关代码为:

//三元组数值有一个特点:那就是在不同位置上的行值相同的元素  //一定是按照列值升序出现的。  //三元组数值有一个特点:那就是在不同位置上的行值相同的元素  //一定是按照列值升序出现的。  #define _CRT_SECURE_NO_WARNINGS  #include <stdio.h>  #include <stdlib.h>  #include <string.h>  typedef struct TRIPLE//三元组成员  {      int row;      int col;      int value;  }TRIPLE;  typedef struct TRIPLE_HEAD//三元组头  {      int rowCount;      int colCount;      int elementCount;      TRIPLE *values;  }TRIPLE_HEAD;  TRIPLE_HEAD *initTriple();  void destoryTriple(TRIPLE_HEAD *triHd);  void showTriple(TRIPLE_HEAD triHd);  TRIPLE_HEAD *revange(TRIPLE_HEAD trip);  TRIPLE_HEAD *revange(TRIPLE_HEAD trip)  {      TRIPLE_HEAD *ntrip = NULL; //new      int p,q,col;    ntrip = (TRIPLE_HEAD *)malloc(sizeof(TRIPLE_HEAD));      ntrip->rowCount = trip.colCount;    ntrip->colCount = trip.rowCount;    ntrip->elementCount = trip.elementCount;    ntrip->values = (TRIPLE *)malloc(sizeof(TRIPLE)*ntrip->elementCount);      if(ntrip->elementCount != 0)    {// 有非零元素则转换      q = 0;      for(col = 1;col <=(trip.colCount);col++)      {        for(p = 0;p < (trip.elementCount);p++)        {          if(trip.values[p].col == col){            ntrip->values[q].row = trip.values[p].col;            ntrip->values[q].col = trip.values[p].row;            ntrip->values[q].value = trip.values[p].value;            q++;          }        }      }      return ntrip;    }}  void showTriple(TRIPLE_HEAD triHd)  {      int i, j, t = 0;      printf("\n");      for (i = 1; i <= triHd.rowCount; i++)      {          for (j = 1; j <= triHd.colCount; j++)          {              if (t < triHd.elementCount && i == triHd.values[t].row && j == triHd.values[t].col){                  printf("%d ", triHd.values[t++].value);              }              else{                  printf("0 ");              }          }          printf("\n");      }  }  void destoryTriple(TRIPLE_HEAD *triHd)  {      free(triHd->values);      free(triHd);  }  TRIPLE_HEAD *initTriple()  {      TRIPLE_HEAD *th;      int row;      int col;      int value;      int i;      th = (TRIPLE_HEAD *)malloc(sizeof(TRIPLE_HEAD));      printf("请输入矩阵的阶数(行 列):");      scanf("%d%d", &th->rowCount, &th->colCount);      printf("请输入有效元素的个数:\n");      scanf("%d", &th->elementCount);      th->values = (TRIPLE *)malloc(sizeof(TRIPLE)* th->elementCount);      for (i = 0; i < th->elementCount; i++)      {          printf("请输入第%d个元素(行 列 值)(共%d个):", i+1, th->elementCount);          scanf("%d%d%d", &row, &col, &value);          th->values[i].row = row;          th->values[i].col = col;          th->values[i].value = value;      }      return th;  }  void main(void)  {      TRIPLE_HEAD *trip, *revTrip;      trip = initTriple();      showTriple(*trip);      revTrip = revange(*trip);      showTriple(*revTrip);//转置之后的稀疏矩阵      destoryTriple(trip);      destoryTriple(revTrip);  }  

2. 十字链表

在十字链表中,同一行的结点和同一列的结点分别顺序循环连接,每个结点既在他所在行的循环链表中又在他所在列的循环链表中
每个结点含有五个域 行号,列号,值,该结点所在行链表后继结点指针,所在列链表后继结点指针

为了处理方便,通常对每个行链表和列链表分别设置一个头结点,并把它们构成带表头结点的循环链表。
为了引用某行某列方便,全部行链表的表头结点和全部列链表的表头结点分别组成数组,这两个数组的首结点指针存于
一个十字链表的头结点中,最后由一个指针指向该头结点。

这里写图片描述

相关代码为:

#include <stdio.h>  #include <stdlib.h>    typedef struct Matrix_ELEMENT //稀疏矩阵成员,值 并指向下一个值    {        int row;        int col;        int value;        struct Matrix_ELEMENT *rowLink;        struct Matrix_ELEMENT *colLink;    };    typedef struct Matrix_ELEMENT MELEMENT;    typedef MELEMENT *LINKS;    //指向一行或者一列的指针    typedef struct CROSS_LINK     {        int rowCount;        int colCount;        /*LINKS *rowLinks;      LINKS *colLinks;*/ //上下两句等价        MELEMENT **rowLinks;        MELEMENT **colLinks;    }CROSS_LINK;    CROSS_LINK *initCrossLink(void);    MELEMENT *findPreCol(MELEMENT *rowLink, int col);    MELEMENT *findPreRow(MELEMENT *colLink, int row);    void destroyCrossLink(CROSS_LINK *cross);    void showCrossLink(CROSS_LINK *cross);    void showCrossLink(CROSS_LINK *cross)    {        int i, j;        MELEMENT *p;        //输出的技巧        printf("矩阵如下:\n");        for (i = 0; i < cross->rowCount; i++)        {            for (p = cross->rowLinks[i], j = 0; p; p = p->rowLink)            {                while (j++ < p->col)                {                    printf("0 ");                }                printf("%d ", p->value);            }            while (j++ < cross->colCount)            {                printf("0 ");            }            printf("\n");        }    }    void destroyCrossLink(CROSS_LINK *cross)    {        //先释放每行指针形成的链表        int i;        MELEMENT *p;        for (i = 0; i < cross->rowCount; i++)        {            while (p = cross->rowLinks[i])            {                p = cross->rowLinks[i];                cross->rowLinks[i] = p->rowLink;                free(p);            }        }        //再释放行链数组和列连数组        free(cross->colLinks);        free(cross->rowLinks);        //最后释放头        free(cross);    }    MELEMENT *findPreRow(MELEMENT *colLink, int row)    {        MELEMENT *p, *q = NULL;        for (p = colLink; p && row >= p->row; p = p->colLink)        {            q = p;        }        return q;    }    MELEMENT *findPreCol(MELEMENT *rowLink, int col)    {        MELEMENT *p, *q = NULL;        for (p = rowLink; p && col >= p->col; p = p->rowLink)        {            q = p;        }        return q;    }    CROSS_LINK *initCrossLink()    {        CROSS_LINK *head;        MELEMENT *mElement, *q;        int row, col;        int value;        printf("请输入稀疏矩阵的阶数(行 列):");        scanf("%d%d", &row, &col);        head = (CROSS_LINK *)malloc(sizeof(CROSS_LINK));        head->rowCount = row;        head->colCount = col;        head->rowLinks = (LINKS *)calloc(sizeof(LINKS),row);        head->colLinks = (MELEMENT **)calloc(sizeof(MELEMENT *), col);        printf("请输入(行 列 值)(行值输入为-1,结束输入):");        scanf("%d%d%d", &row, &col, &value);        while (row != -1) //(row != EOF)        {            //将row、col、he value的值对应到相应的元素            mElement = (MELEMENT *)calloc(sizeof(MELEMENT), 1);            //mElement->rowLink = NULL;            //mElement->colLink = NULL;            mElement->row = row;            mElement->col = col;            mElement->value = value;            if (head->rowLinks[row] == NULL)                head->rowLinks[row] = mElement;            else            {                q = findPreCol(head->rowLinks[row], col);                if (q == NULL)                {                    mElement->rowLink = head->rowLinks[row];                    head->rowLinks[row] = mElement;                }                else                {                    mElement->rowLink = q->rowLink;                    q->rowLink = mElement;                }            }            if (head->colLinks[col] == NULL)                head->colLinks[col] = mElement;            else            {                q = findPreRow(head->colLinks[col], row);                if (q == NULL)                {                    mElement->colLink = head->colLinks[col];                    head->colLinks[col] = mElement;                }                else                {                    mElement->colLink = q->colLink;                    q->colLink = mElement;                }            }            printf("请输入(行 列 值)(行值输入为-1,结束输入):");            scanf("%d%d%d", &row, &col, &value);        }        return head;    }    void main(void)    {        CROSS_LINK *cLink;        cLink = initCrossLink();        showCrossLink(cLink);        destroyCrossLink(cLink);        system("pause");    }

如果对稀疏矩阵某行或某列整体做某处理,可能会使原来为零的元素变为非零,而原来非零的元素变为零,
对于这种场合,稀疏矩阵应该采用十字链表来表示

KMP算法

相关代码为:

#include <stdio.h>  #include <string.h>  int next[32] = {-999};  /* 返回模式串T在母串S中第pos个字符的位置 */  /* 调试小技巧 print x = value 或 set var x = value 可以改变gdb运行时变量的值 */  int index_BM(char *S, char *T, int pos)  {      int i;      int j;      i = pos;      j = 0;       while ( (i < strlen(S)) && (j < strlen(T)) )      {          if (S[i] == T[j])          {              i++;              j++;          }          else          {              i = i - j + 1;               j = 0;          }      }      /* 注意strlen(T)意味着j的取值范围为0 ~ (strlen(T) - 1) */      if (strlen(T) == j)      {          return i - strlen(T);      }      else      {          return -1;      }  }  void get_next(char *T, int *next)  {      int k = -1;      int j = 0;      next[j] = k;      while (j < strlen(T))      {          if ( (k == -1) || (T[j] == T[k]) ) //注意等号是==,而不是=          {              ++k; // 注意是先加后使用              ++j;              next[j] = k;          }          else          {              k = next[k];           }      }  }  int index_KMP(char *S, char *T, int pos)  {      int i;      int j;      i = pos;      j = 0;       while ( (i < strlen(S)) && (j < strlen(T)) )      {          /* j = -1 表示next[0], 说明失配处在模式串T的第0个字符。所以这里特殊处理,然后令i+1和j+1。*/          if ( (j == -1)  || S[i] == T[j])          {              i++;              j++;          }          else          {              j = next[j];          }      }      if (strlen(T) == j)      {          return i - strlen(T);      }      else      {          return -1;      }  }  void print_next(int next[], int n)  {     int i;     for (i = 0; i < n; i++)      {         printf("next[%d] = %d\n", i, next[i]);     }  }  int main(void)  {      char *s = "ababcabcacbab";      char *t = "abcac";      int pos = 0;      int index;      printf("================ BM ==============\n");      index = index_BM(s, t, pos);      printf("index = %d\n", index);      printf("================ KMP ==============\n");      get_next(t, next);      print_next(next, strlen(t));      index = index_KMP(s, t, pos);      printf("index = %d\n", index);  }  

求next函数的值

next[j] = 0         j = 1;next[j] = max{k|1 < k < j,'p1p2...pk-1' = 'pj-k+1pj-k+2...pj-1'}next[j] = 1 其他情况

树和二叉树

原创粉丝点击