软考复习:数据结构基础(1.1线性表)
来源:互联网 发布:关于考研的淘宝店铺 编辑:程序博客网 时间:2024/05/20 06:51
1.1 线性表
线性表的基本运算
1. 查找运算
在线性表中查找具有给定键值的结点
2. 插入运算
在线性表第i(0<=i<=n-1)个结点的前面或者后面插入一个新的结点
3. 删除运算
删除线性表的第i(0<=i<=n-1)个结点。
4. 其他运算
- 统计线性表中节点的个数
- 输出线性表各节点的值
- 复制线性表
- 线性表分拆
- 线性表合并
- 线性表排序
- 按某种规则整理线性表
线性表的存储
顺序存储
顺序存储通常用一个数组。
优点:能随机存取线性表中的任何一个结点
缺点:1,数组大小通常是固定的,不利于任意增加或减少线性表节点的个数
2,插入和删除线性表的结点时,要移动数组中的其他元素,操作复杂链式存储
链式存储是用链表存储线性表
优点:每个结点的实际存储位置是任意的,插入和删除操作方便,不需要移动表元
缺点:1,每个节点增加了一个后继指针成分,增加了存储空间
2,不便随机访问线性表的任一结点
在线性表中插入新结点
- 顺序存储
设线性表结点类型为整形,插入之前有n个结点,把值为x的结点插入线性表的第i个位置上
插入步骤为:
1. 检查插入要求的有关参数的合理性
2. 把原来的第n个结点到第i个结点依次往后移动一个数组元素位置
3. 把新结点放在第i个位置上
4. 修正线性表的结点个数
- 链式存储
在廉洁存储线性表中插入一个键值为x的新结点,分为如下4种情况
- 在某指针p所指结点之后插入
- 插在首结点之前,使待插入结点成为新的首结点
- 接在线性表的末尾
- 在有序链表中插入,使新的线性表任然有序
删除线性表的结点
- 顺序存储
删除步骤:
1. 检查删除要求的有关参数的合理性
2. 把原来第i+1个表元至第n个结点依次向前移动一个数组元素位置
3. 修正线性表结点个数
- 链式存储
删除步骤:
1. 如链表为空链表,则不执行删除操作
2. 如链表的首结点的值为指定值,更改表的头指针为指向首结点的后继结点
3. 在链表中寻找指定值的结点
4. 将找到的结点删除
1.1.1 栈
顺序存储
可以用顺序存储线性表来表示栈,为了指明当前执行插入和删除运算的栈顶位置,需要一个地址变量top
指出栈顶结点在数组中的下标链式存储
可以用链表实现。
1.1.2 队列
具有先进先出的特征
顺序存储
随着一系列进队和出队运算,会出现前端空着,而队列空间已用完的情况
一种可行的方法是把队列中的结点一刀队列的前端,修改头指针和尾指针
另一种更好的解决方法是采用循环队列循环队列就是将队列数组的第一个元素与最后一个元素连接起来。
由于其中会造成队空和队满的条件同为head==tail。因此可采用只剩下一个空闲结点,就认为队列已满链式存储
1.1.3 稀疏矩阵
如果一个矩阵的元素绝大部分都为零,则称为稀疏矩阵。若直接用一个二维数组表示稀疏矩阵会浪费大量的
内存空间,通常采用三元组数组或者十字链表两种方法来表示稀疏矩阵
三元组数组
稀疏矩阵中的每个非零元素都用一个三元组来表示,即非零元素的 行号,列号,和他的值
然后按照某种顺序将全部非零元素的三元组存入一个数组中
如果只对稀疏矩阵的某些单个元素进行处理,则宜采用三元组表示
相关代码为:
//三元组数值有一个特点:那就是在不同位置上的行值相同的元素 //一定是按照列值升序出现的。 //三元组数值有一个特点:那就是在不同位置上的行值相同的元素 //一定是按照列值升序出现的。 #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 其他情况
树和二叉树
- 软考复习:数据结构基础(1.1线性表)
- 复习 [数据结构] ---- 线性表
- 数据结构复习-线性表
- 【数据结构复习】线性表
- 一步一步复习数据结构和算法基础-线性表
- 数据结构复习-基础、线性表、栈、队列、串
- 复习(数据结构:java):线性表(数组):基础类设计
- 数据结构复习篇:线性表
- 数据结构复习篇:线性表
- 数据结构复习之【线性表】
- 数据结构重新复习-线性表
- 数据结构复习一:线性表
- 《数据结构》复习笔记--线性表
- 数据结构复习之线性表
- 数据结构之【线性表】--复习
- 复习(数据结构):线性表 : C
- 复习-数据结构之线性表
- 数据结构复习之线性表
- 4.3 数据的格式化键盘输入习题4
- shell 单实例(2)
- 初步学习c语言
- UITableView 优化
- 毕业设计系统基本框架 【basic 1.0】springMVC+mybatis+mysql
- 软考复习:数据结构基础(1.1线性表)
- getElementsByClassName兼容新老浏览器方法
- Java 中,File 类的一些常用操作比如过滤,遍历等操作
- 朴素贝叶斯
- 第一个爬虫程序
- Go func 练手
- Flex 布局教程
- 无名管道通信
- 【网络编程】TCP数据报格式