390 likes | 509 Views
段景山. 软件技术基础. 线性结构. 制作 主讲. 段景山. 栈结构. 2 、堆栈 stack. 栈是特殊的线性表,仅在表的一端进行插入或删除操作. 出栈. 入栈. 栈顶. an. 是抽屉一类物理实体的逻辑抽象 类似仓库、抽屉的结构. a2. 栈底. a1. 特点:( 1 )对栈内数据的操作总在栈顶进行 ( 2 )数据进栈称为“压入” push ( 3 )数据出栈称为“弹出” pop ( 4 )遵循“后进先出”的原则 LIFO. 用数组实现栈. 2.1 用数组实现栈. 栈顶元素 所在位置. a[max].
E N D
段景山 软件技术基础 线性结构 制作 主讲 段景山
栈结构 2、堆栈 stack 栈是特殊的线性表,仅在表的一端进行插入或删除操作 出栈 入栈 栈顶 an 是抽屉一类物理实体的逻辑抽象 类似仓库、抽屉的结构 ... a2 栈底 a1 特点:(1)对栈内数据的操作总在栈顶进行 (2)数据进栈称为“压入”push (3)数据出栈称为“弹出”pop (4)遵循“后进先出”的原则LIFO
用数组实现栈 2.1用数组实现栈 栈顶元素 所在位置 a[max] a[0]为栈底,top为栈顶 new_one ... ... (1)定义 a[top] 栈顶 typedef struct stack_type{ elemtype data[MAXNUM]; int top; }stack_type; ... a2 a[1] a1 a[0] (2)压入 push 当新元素入栈时,栈顶上移,新元素放在栈顶。 stack.top = stack.top + 1; stack.data[stack.top] = new_one;
用数组实现栈 (3)弹出 pop a[max] 从栈顶移出一个数据。 out 栈顶 a[top] 栈顶元素拷贝出栈,栈顶下移 ... out = stack.data[stack.top]; stack.top = stack.top - 1; ... a2 elemptype pop(stack_type *stack){ elemtype out; if(stack->top <= 0) error(3); else{ out = stack->data[stack->top]; stack->top = stack->top -1; } return out; } a[1] a1 a[0]
用数组实现栈 (4)栈空判断 stack.top == 0 stack.top a[0] stack.top < 0 栈顶元素所在位置 栈满判断:stack.top >= MAXNUM - 1; (5)置栈空 stack.top = -1;
proc B( ) ...... ...... call C( ) ...... proc C( ) ...... ...... ...... proc A( ) ...... call B(); ...... 用数组实现栈 (6)栈的应用 例 程序的嵌套,中断的嵌套 程序C 程序B 程序A
proc B( ) ...... ...... call C( ) ...... proc C( ) ...... ...... ...... proc A( ) ...... call B( ); ...... 用数组实现栈 (6)栈的应用 程序的嵌套,中断的嵌套 程序C 程序C 程序B 程序A 程序B 程序A
an a1 a2 …… 用链表实现栈 • 2.2用链表实现栈 入栈 出栈 head top 栈顶在 表头 (1)定义 typedef struct lstack_type{ node_type * top; int length; }lstack_type;
用链表实现栈 (2)压入push void push(stack, new_node){ new_node->next = stack->top; stack->top = new_node; stack->length ++; } …… a1 stack->top (3)弹出pop node_type * pop(stack){ node_type* out; out = stack->top; stack->top = stack->top->next; stack->length --; return out; } new
用链表实现栈 (4)栈空判断 int empty(stack){ if(stack.top == NULL) return YES; else return NO; } stack.top == NULL; (5)置栈空 能否简单的使用 stack.top = NULL ? 如果栈中还有链点,必须逐个将链点占用的空间释放 void clean(stack){ node_type * temp; while( ! empty(stack)){ temp = pop(stack); free(temp);} } 1、逐个将链点弹出 2、释放链点空间
队列 • 3、队列 • 类似于排队机制的结构 • 队列是特殊的线性表, • 节点的插入仅限于在表尾进行, • 节点的删除仅限于在表头进行 入队 出队 队尾 队头
队列 • 特点: • (1)对队列的操作在表的两端进行 • (2)仅在队尾加入节点——入队enqueue • (3)仅在队首移出节点——出队dequeue • (4)遵循“先进先出”的原则——FIFO 出队 入队 队头 队尾
用数组实现队列 • 3.1用数组实现队列 • (1)定义 a[0] a[1] ... a[n] ... MAX 队首 队尾 rear front typedef struct queue_type{ elemtype data[MAXNUM]; int front; int rear; }queue_type;
rear front 用数组实现队列 • (2)入队与出队 移元素? 移队首、尾指针 入队 出队 入队 出队 入队 数组空间溢出而使操作出错
front rear ( ) % MAXNUM 用循环数组实现队列 • 3.2用循环数组实现队列 入队 rear = rear + 1 % 整除取余 设MAXNUM = 5,rear=4 则新元素加入队列后: rear =(4+1)% 5=0,新元素放在a[0]内
front front rear rear 用循环数组实现队列 队列元素位置?
rear front front 用循环数组实现队列 • 队空条件 • 队满条件 front == rear 如果rear表示队尾节点的位置则有一个节点的队列的指针情况和队空时相同 front rear rear (rear + 1) % MAXNUM = = front
rear front front 用循环数组实现队列 • 队空条件 • 队满条件 front == rear 定义:rear为指向队尾下一个可存放节点的位置 队列满时还有一个空位置 rear (rear + 1) % MAXNUM = = front
front rear 用循环数组实现队列 • 入队算法 队列已满? void enqueue(queue,new_one){ if( (queue->rear + 1) % MAXNUM == queue->front) error(1); else{ queue->data[queue->rear] = new_one; queue->rear = (queue->rear +1) % MAXNUM; } } 队列尾部放入新节点 队尾指示向后移动一格
front rear 用循环数组实现队列 • 出队算法--课堂练习 elemtypedequeue(queue){ elemtype out; if( queue->rear == queue->front) error(2); else{ out =queue->data[queue->front]; queue->front = (queue->front +1) % MAXNUM; } return out; }
front 用循环数组实现队列 • 思考:在循环队列的第K个元素后插入一个新元素--插队 • 如何确定aK的位置? • 如何搬移节点,以腾出空位放入新元素? rear
an a1 a2 …… 用链表实现队列 • 3.3用链表实现队列 front rear (一)定义 typedef struct lqueue_type{ node_type * front; node_type * rear; int length; }
an a1 a2 …… 用链表实现队列 • (二) 入队 • 新链点插入到队尾 • 注意:队列为空时,rear和front都要指向新元素 • (三) 出队 • 删除队首链点 • 注意:当队列被删空时,rear指针要置空 new_node->next = NULL; list->rear ->next = new_node; rear front temp = list->front; list->front = list->front->next;
元素 字符 字符串中字符的先后次序 元素间的关系 串结构 • 4、串 串即字符串: 由零到多个字符组成的连续有限序列 • 串是一种线性结构 • 串符合线性表的特性(特别是顺序表) • 字符串的特殊性在于对串有一些特殊的操作 线性
串结构 • 4.1访问操作 • 基本访问: • 根据字符在串中位置获得字符; • 根据字符获得它在串中位置 • 遍历:逐个访问串中字符 • 部分访问(求子串): • 获得串中指定位置开始的多个元素 • 获得子串在串中的位置 课堂练习: 以姓名为例分别给出各种操作应用示例。 如: Duan Jingshan 取得J所在的位置可以获得姓的长度
串结构 • 4.2插入 • 基本插入:在串中指定位置插入一个字符 • 子串插入:在串中指定位置插入多个字符 • 4.3删除 • 基本删除:在串中指定位置删除字符 • 子串删除:在串中指定位置删除多个字符 • 4.4其它操作 • 串连接:一个串连在另一个串的后面,形成新串 • 求串长、串比较、子串替换 ...... 串的操作是文字处理的基础
串结构 • 4.5串的实现 • (1)字符数组(用数组实现串) • 紧缩格式: • 数组每一个单元类型都是字符型,可放入一个字节的字符 • 非紧缩格式: • 数组的单元不是字符型——2~4个字节 a[0] a[0] char a[4]; long a[4]; D D a[1] a[1] u u 共16字节 a[2] a[2] 共4字节 a a a[3] a[3] n n
串结构 • (2)字符链表(用链表实现串) • 链表的每个链点的元素域放入一个字符 • 操作方便,但空间开销大 • 链点元素域占一个字节 • 链点指针域占四个字节 • 开销为4/5 s t u d e n t
二维数组(矩阵) j • 5、二维数组 • 行关系,列关系均是线性关系 • 5.1二维数组的顺序存放 • (一)行优先存放 • 计算aij的存放位置: ... a11 a12 a21 ... i aij ... amn ... a11 a12...a1na21a22...ai1 ai2 ...ain...am1 am2 ...amn 设每个元素占据S个存储单元 Loc(aij) = Loc(a11) + (( i - 1)*n + (j - 1))*S 计算前面有多少个元素
二维数组 • (二)列优先存放 a11 a21...am1a12a22...am2a1j a2j ...aii...a1n a2n ...amn Loc(aij) = Loc(a11) + (( j - 1)*m + (i - 1))*S j ... a11 a12 a21 ... i aij ... amn ...
data 行指针 列指针 二维数组 • 5.2矩阵的链接存储 十字链表法 a11 a12 a1i a1n a21 a22 ...... a31 a32 ...... am1 am2
二维数组 ... 1 • 5.3矩阵的压缩存储 • (1)对称矩阵,三角矩阵的压缩 • 对称矩阵:a[ i , j ] = a[ j , i ] • 三角矩阵:上三角为0,或下三角为0 只存储上或下三角内的元素,节约近一半的存储空间 3 4 0 5 2 6 2 4 3 7 1 5 3 6 5 a11 a21a22a31a32a33a41…aii...an1 an2 ...ann
二维数组 ... • (1)对称矩阵,三角矩阵的压缩 1 3 4 0 5 2 6 2 4 3 7 1 5 3 6 5 a11 a21a22a31a32a33a41…aii...an1 an2 ...ann 1+2+3+…+(i-1) i >= j 时,元素位于下三角 Loc(aij) = Loc(a11) + ( i ( i - 1) / 2 + ( j - 1))*S i < j 时,元素位于上三角 Loc(aij) = Loc(a11) + ( j ( j - 1) / 2 + ( i - 1))*S
aij 行值,列值,元素值 二维数组 • (2)稀疏矩阵 • 矩阵中的非零元素很少,分布没有规律 • 利用三元存储法 • 先形成三元矩阵 • 再按照行优先顺序方式存储。 行数 列数 第一行 非零元素个数 第一个非零元素 行值 列值 元素值 = AMN 第二个非零元素 行值 列值 元素值 ... ...
二维数组 • 稀疏矩阵压缩存储例 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 = X48 0 0 6 0 0 0 5 0 0 0 3 0 0 0 0 0 4 8 5 行数 列数 非零元素个数 1 1 1 = A63 2 1 4 6 3 2 5 3 7 4 1 3 a[18] = {4,8,5,1,1,1,2,4,1,3,2,6,3,7,5,4,1,3}
二维数组 • 稀疏矩阵三元组定义 • 1)定义三元组元素 • 2)定义三元组 typedef struct tuple3tp{ int row_num; /*行号*/ int col_num; /*列号*/ elemtype value; /*元素值*/ } tuple3tp typedef struct tuple3{ int row; /*行数*/ int col; /*列数*/ int num; /*非零元素个数*/ tuple3tp data[ MAXNUM];/* 三元组*/ }tuple3;
上机习题:稀疏矩阵求转置 void transposition(tuple3 * a, tuple3 * b) { int col, i,num; b.row = a.col, b.col = a.row, b.num = a.num; num = 0; for(col = 0; col < a.col ; col ++){ for(i = 0; i < a.num; i ++){ if( a[ i ].col_num = = col){ b[ num ].col_num = a[ i ].row_num; b[ num ].row_num = a[ i ].col_num; b[ num ].value = a[ i ].value; num += 1; } }} } 转置后的矩阵仍以三元组法,行优先存放 注意:部分“.”在实际程序中应该为“->” 思考:稀疏矩阵相加
小结 数据逻辑结构 数据结构 数据存储结构 算法 用数组实现(顺序XX) 线性结构、栈、队列、串 用链表实现(链接XX) 顺序表与线性链表(单链表、双链表) 顺序栈与链栈(应用--回溯性) 与链队列 与 循环链表 ? 顺序队列 循环队列 二维数组的存储(行优先、列优先,定位) 数组的压缩(压缩定位,三元组法)
作业 • 教材71页12、13、14