线性表的插入和删除只能在一端进行,这种线性表即为栈,允许插入删除的一端为栈顶。(栈是先进后出)
栈的生成方式:
向下生成的栈。栈顶在高地址端(下方)。 入栈为top++,出栈为top-- ;
向上生成的栈。栈顶在低地址端(上方)。入栈为top--,出栈为top++;
栈顶指针有两种指示方式:
栈顶指针指向空单元 ;
栈顶指针指向最后写入的元素。
根据栈顶指针的指示方式不同,入栈和出栈时的指针操作也不同。
例如: 栈顶指向空单元时。 入栈时先写元素,后修改栈顶指针。出栈时先修改栈顶指针,后读元素。
栈:
1静态顺序栈 ,即用数组描述。(初始化时,top = -1 ) 默认也是指向栈顶元素。
2动态顺序栈 ,定义一个栈时,预先值定义栈的头结点类型,栈存储空间动态申请。(有一个top指针(栈顶),一个base指针(栈底)) 。
双栈 , 为了共享存储空间,两个栈用一块存储空间存放,两栈栈顶相对()。当这段存储空间用完,即两个栈顶指针相邻。
多栈 。
初始化一个栈:
先调用malloc申请栈空间 (即栈满时所用的存储空间)。 S.base = -----malloc -------
判断是否申请成功。if(!S.base) exit (OVERFLOW) ;
申请成功后, S.top = S.base ;再返回OK。
realloc , 改变指针所指存储空间大小 realloc(*ptr , size) ,size可大于原先内存,也可小于原先内存(会丢失数据) ,此函数需要包含 stdlib.h ,有的要包含 malloc.h
入栈操作:
先判断是否栈满 if(S.top — S.base >= MAXSIZE)
栈满,再申请存储空间 S.base = realloc(S.base , size)
修改栈顶指针, S.top = S.stacksize + S.base (stacksize为原栈大小)
入栈 S[top++] = e ; return OK;
出栈操作:
先判是否空栈 ,
出栈 e = S[top--]
链栈 ,可对应链表,只不过多了了栈元素的节点类型的top指针。
(链栈为空时,top == NULL ,链栈为非空时,top 指向最头结点,即最后一个进栈的节点)
链栈 入栈:
先申请一个节点空间, 并让节点存储数据,
再类似于单链表的头插法。 S->next = top ; top = s ;
链栈 出栈:
先判是否空栈 if(!top) return ERROR ;
否则 , e = top->data ; p = top ; top = top ->next ; free (p) ;
队列:
限制线性表的插入在表一端进行(队尾),限制线性删除的一端称为(队首)。
链队:
链式存储的队列
链队进(Q封装了队列的队首和队尾指针)
队尾进,先申请节点, --- malloc --- ;(假设要进队列的节点为p)
p->next = NULL ; Q.rear = p ; return OK ;
链队出
先判断是否空队列(Q.rear == Q.front)
非空队列,则队首出。 p = Q.front->next ; e = p->data ; Q.front->next = p->next ; (从队首删除了一个元素)
再判尾节点是否为p,即删除的节点是否为尾节点,(Q.rear == p) ,如果是,则为空队列,Q.rear = Q.front ; free(p); return OK ;
清空链队列:
p = Q.front ->next ; while(p) { q = p ; p = p->next ; free q ; } Q.rear = Q.front (尾指针指向头结点);
撤销链队类(与清空链队列的区别是将释放头节点的内存空间,即 free(Q.front) //并让头指针和尾指针指向相同节点):
while(Q.front) { Q.rear = Q.front->next ; free(Q.rear);Q.front = Q.rear ;}
顺序队列(队尾进,队首出)
顺序队列,包含队列存储空间首地址,队头队尾指针(数组的索引)
申请一个顺序队的存储空间:Q.base = (Q--- *) malloc (MAXSIZE * sizeof(Q---));
由于空队时, Q.front = Q.rear = -1 。则入队时,Q.base[ ++Q.rear] = e ; 出队时为,e = Q.base[++Q.front] ;
顺序队列的“假溢出”现象。(即随着进队出队的不断进行,会使队列整体向后移动,就会出现队尾指针移到最后,但是存储空间却并未被完全占满,即队首前还有空间未被占用。)
此时队列的长度为 rear - front
循环队列:
入队时: Q.rear = (Q.rear+1)% MAXSIZE ;
出队时: Q.front = (Q.front+1)%MAXSIZE;
此时队列的长度为 length = (Q.rear - Q.front + MAXSIZE)% MAXSIZE 加上MAXSIZE是为了防止队满情况时(front == rear)
队空和队满均为 front == rear 的解决办法
1是:定义一个存储队列中元素个数的变量NUM ,当NUM为0时,队空,当NUM为MAXSIZE时,对满。
2是:牺牲一个元素空间,队满的情况为,(rear+1)%MAXSIZE == front ;
入队操作, Q.rear = (Q.rear+1)%MAXSIZE ;
Q.base[Q.rear] = item ; return OK ;
出队操作, Q.front = (Q.front+1)%MAXSIZ ;
item = Q.base[Q.front] ; // 书上的顺序与此相反,但我觉得有问题。因为front指向空,所以应该先操作指针再进行读取元素。
双端队列 , 在两端都可以进行入队和出队操作的队列称为双端队列。这种队列可以看成是由两个对底的双栈所构成的队列。
其中,双端队列还可细分为:
输入受限双端队列,即允许在一端只进行插入操作,在另一端可以进行插入和删除。
输出受限双端队列,允许在一端只进行删除操作,在另一端可以进行插入和删除。