为防止数据丢失, 在进栈操作之前应判断是否栈满
顺序栈使用C定义如下:
const int maxsize =6;
typedef struct seqstack {
DataType data[maxsize];
int top;
} seqStk;
maxsize 为顺序栈的容量
data[maxsize] 存储栈中数据元素的数组
top 标志栈顶位置的变量, 范围为0到maxsize-1
int InitStack(SeqStk *stk){
stk->top =0;
return 1;
}
int EmptyStack(SeqStk *stk){
if (stk->top ==0) return 1;
else return 0;
}
int Push(SeqStk *stk, DateType x){
if (stk->top == maxsize-1)
{
error("栈满"); return 0'}
else{
stk->top++;
stk->data[stk->top] =x;
return 1;
}
}
int Pop(SeqStk *stk){
if (stk->top ==0){
error("栈空");
return 0;
}
else{
stk->top--;
return 1;
}
}
DataType GetTop(SeqStk *stk){
if (EmptyStack(stk)) return NULLData;
else return stk->data[stk->top]
}
栈的链接实现称为链栈, 链栈可以用带头结点的单链表实现
LS指向链表的头结点, 首结点即是栈顶结点, LS->next指向栈顶结点, 尾结点为栈底结点. 链栈不用考虑容量的大小.
C语言定义如下:
typedef struct node {
DataType data;
struct node *next;
}LkStk;
void InitStack(LkStk *LS){
LS = (LkStk *)malloc(sizeof(LkStk));
LS->next = NULL; // 建立一个空栈
}
int EmptyStack(LkStk *LS){
if (LS->next==NULL) return 1;
else return 0;
}
void Push(LkStk *LS, DataType x){
LkStk *temp;
temp = (LkStk *)malloc(sizeof(LkStk)); // 指向申请的新结点
temp->data = x; // 新结点的值赋为x
temp->next=LS->next; // 新结点的next域指向原来的栈顶结点
LS->next = temp; // 指向新的栈顶结点
}
int Pop(LkStk *LS){
LkStk *temp;
if (EmptyStack(LS)) return 0;
else {
temp = LS->next;
LS->next = temp->next;
free(temp);
return 1;
}
}
这里多想一点:
为什么不使用LS->next=LS->next->next
这样的方式直接将栈顶指向次栈顶结点呢?
若使用此种方式, 原栈顶结点还是存在的,且还占用内存空间, 因为没有释放它,
所以这里引入 temp 指针, 第一步: temp指向栈顶, 第二步: 将原栈顶结点指向次栈顶, 第三步,释放temp.
5. 取栈顶元素
DataType GetTop(LsStk *LS){
if (EmptyStack(LS)) return NULLData;
else {
return LS->next->data; // 返回栈顶元素
}
}
递归: 如果一个函数或数据结构的定义中又应用了它自身, 那么这个函数或数据结构称为递归定义的, 简称递归的.
递归定义不能是"循环定义", 必须以下两个条件:
const int maxsize=20;
typedef struct seqqueue{
DataType Data[maxsize]; //一维数组, 存储队列中的数据元素
int front, rear; // front指向<重要: 队首元素的前一个单元>, rear指向实际的队尾元素单元
} SeqQue;
SeqQue SQ;
Data: 一维数组, 存储队列中的数据元素
front: 指向<重要: 队首元素的前一个单元>
rear: 指向实际的队尾元素单元
为什么不使用线性表, 而使用循环线性表?
参考p72页,
循环队列的基本运算如下:
void InitQueue(CycQue CQ){
CQ.front = 0;
CQ.rear = 0;
}
int EmptyQueue(CycQue CQ){
if (CQ.front == CQ.rear) return 1;
else return 0;
}
void EnQueue(CycQue CQ, DataTye x){
if ((CQ.rear+1)%maxsize == CQ.front) {
error("队列已满");
return 0;
}
else {
CQ.rear = (CQ.rear+1) % maxsize;
CQ.data[CQ.rear] = x;
return 1;
}
}
int OutQueue(CycQue CQ){
if (EmptyQueue(CQ)) {
error("队列为空了");
return 0;
}
else{
CQ.front = (CQ.front+1)%maxsize; //出队列成功
return 1;
}
}
DataType GetHead(CycQue CQ){
if (EmptyQueue(CQ) return NULLData;
else{
return CQ.data[(CQ.front+1)%maxsize];
}
}
typedef struct LinkQueueNode{
DataType data;
struct LinkQuequeNode *next;
}LkQueNode;
typedef struct LkQueNode{
LkQueNode *front, *rear;
}LkQue;
LkQue LQ;
void InitQueue(LkQue *LQ){
LkQueNode *temp;
temp = (LkQueNode *)malloc(sizeof(LkQueNode));
LQ->front = temp;
LQ->rear = temp;
(LQ->front)->next = NULL;
}
int EmptyQueue(LkQue *LQ){
if (LQ.front == LQ.rear) return 1;
else return 0;
}
void EnQueue(LkQue *LQ, DataType x){
LkQueNode *temp;
temp = (LkQueNode *).malloc(sizeof(LkQueNode));
temp->data = x;
temp->next = NULL;
(LQ->rear)->next = temp; // 新结点入队列
LQ->rear = temp; // 置新的队列队尾结点
}
int OutQueue(LkQue *LQ){
LkQueNode *temp;
if (EmptyQueue(LQ)){
error("队列为空");
return 0;
}
else{
temp = LQ->front->next; // temp 指向首结点
LQ->front->next = temp->next; // 修改头结点的指针,使其指向新的首结点
if (temp->next ==NULL);
LQ->rear = LQ->front;// 无首结点时, front和rear都指向头结点
free(temp);
return 1;
}
}
DataType GetHead(LkQue LQ){
LkQueNode *temp;
if (EmptyQueue(LQ)) return NULLData;
else {
temp = LQ.front->next;
return temp->data; //返回队列首结点元素
}
}
一维数据元素在内存单元地址是连续的, 二维数据可以有种存储方法; 一种以行为主序存储,另一种以列为主序存储. 在类C语言中, 数组采用以行序为主序的存储方法.
数组元素的存储位置是下标的线性函数.(p82)
loc[i, j] = loc[0,0] + (n*i +j)*k
在数值分析中,经常出现一些高阶矩阵, 这些高阶矩阵中有许多值是相同的元素或零元素, 为了节省存储空间, 对这类矩阵采用多个值相同的元素只分配一个存储空间, 零元素不存储的策略, 这一方法被称为矩阵的压缩存储.
如果值相同的元素或零元素在矩阵中分布有一定规律, 称此类矩阵为特殊矩阵
矩阵的非零元素个数很少的矩阵称为稀疏矩阵
设有a[9,9]
那么a[4,5]的存储位置k怎么计算:
因为数组连续存储在内存单元中, 因此只要知道了首元素的位置, 又是采用行为主序存储的方式,
因此, 算法就是loc[0,0]的位置 + 4(在第4行)*9(每行有9个元素)+5(第5个元素)
假设loc[0, 0]位置为0, 则 a[4, 5]位置为: 41
特殊矩阵之对称矩阵(p82)
若一个N阶方阵A中元素满足aij = aji 且i>=0, j<=n-1, 则A称为三角矩阵
个人的理解 :
这个就像99乘法表一样的对称矩阵
设有: a[9, 9],
则有 a[2,3] = a[3, 2]
则可以将其存入9*(9+1)/2 = 45个存储单元中,
实际验证下哈: 原本是需要 9*9=81个存储单元, 对角线如a11, a22, a33之类的, 共需要9个单元, 剩下的都是对称单元, 因此还需要 (81-9)/2=36单元, 再加上对角线的9个单元, 36+9=45个存储单元,
给出的对称矩阵只需要n(N+1)/2, 公式是正确滴 哈哈
这个公式并不适用 a[9, 8]这样的结构
假设loc[0,0]的位置是0, 那么a[4, 5]的位置即是 (4+1)*4/2 + 5 = 15,
那么a[5, 4]元素的位置K怎么计算?
这就简单了呀, 因为a[5, 4] = a[4, 5], 所以位置也是15了, 哈哈
三角矩阵(p83)
以主对角线为界的上(下)半部分是一个固定值C或零, 这样的矩阵就是上(下)三角矩阵.
稀疏矩阵
假设M行N列的矩阵有T个非零元素, 且T<=M*N, 则矩阵称为稀疏矩阵.
说白了只记录值不为零的行列号
如: 使用三元组表((0, 1, 5), (2, 1, -1))
意思即为: a[0,1]=5, a[2, 1] = -1,其它均是0值,