软考复习:数据结构基础

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. 修正线性表的结点个数

  5. 链式存储

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

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

删除步骤:

  1. 检查删除要求的有关参数的合理性

  2. 把原来第i+1个表元至第n个结点依次向前移动一个数组元素位置

  3. 修正线性表结点个数

  4. 链式存储

删除步骤:

  1. 如链表为空链表,则不执行删除操作
  2. 如链表的首结点的值为指定值,更改表的头指针为指向首结点的后继结点
  3. 在链表中寻找指定值的结点
  4. 将找到的结点删除
1.1.1 栈
  1. 顺序存储
    可以用顺序存储线性表来表示栈,为了指明当前执行插入和删除运算的栈顶位置,需要一个地址变量top
    指出栈顶结点在数组中的下标

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

1.1.2 队列

具有先进先出的特征

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

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

  1. 链式存储
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 其他情况

树和二叉树

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值