栈做为一种限定性的线性表,是将线性表的插入和删除操做限制为仅在表的一端进行。算法
/* 栈的常见操做: 1.初始化栈 2.元素进栈 3.元素出栈 4.栈的遍历 5.判断栈是否为空栈 6.清空整个栈 */ # include <stdio.h> # include <stdlib.h> typedef struct Node { int date; struct Node * pNext; }NODE,* PNODE; typedef struct Stack { PNODE pTop; PNODE pBottom; }STACK, * PSTACK; void init(PSTACK pS) { pS->pTop = (PNODE)malloc(sizeof(NODE)); if (NULL == pS->pTop) { printf("动态内存分配失败"); exit(-1); } else { pS->pBottom = pS->pTop;//若是分配成功的话,这两个节点都指向 同一个节点(头节点) pS->pTop->pNext = NULL; //模拟最后的那个“头节点”pS->Bottom->pNext = NUll 也是同样 } } void push(PSTACK pS, int val) { PNODE pNew = (PNODE)malloc(sizeof(NODE)); pNew->date = val; pNew->pNext = pS->pTop;//按照逻辑来的话,进栈时,新的元素会在栈顶,因此要pNext->pTop pS->pTop = pNew; //把新的入栈的元素做为栈的top } void traverse(PSTACK pS) { PNODE p = pS->pTop; while (p != pS->pBottom) { printf("%d ",p->date); p = p->pNext; } printf("\n"); return; } bool empty(PSTACK pS) { if(pS->pTop == pS->pBottom) return true; //若是为空,返回true(证实是空的) else return false; } //把pS所指向的栈出栈一次,并把出栈的元素存入pVal形参所指向的变量中, //若是出栈成功,返回true,不然返回false bool pop(PSTACK pS,int * pVal) { if (empty(pS))//pS 自己存放的就是S的地址,直接返回给empty()函数 { return false; } else { //首先须要一个指针r来指向 栈顶元素,可是若是是pS->pTop = pS->pNext 的话 //内存就没有释放,形成内存泄漏,因此这个方法不可取。 PNODE r = pS->pTop; *pVal = r->date; pS->pTop = r->pNext;//r 指向栈顶,因此把r的next域赋给栈顶 free(r); r = NULL; return true; } } //清空 void clear(PSTACK pS) { if(empty(pS)) { return; } else { PNODE p = pS->pTop; PNODE q = NULL; while(p!=pS->pBottom) { q = p->pNext; free(p); p = q; } //清空以后pTop 的值必定要改写 pS->pTop = pS->pBottom; } } int main(void) { STACK S; int val; init(&S);//对栈进行初始化 ,去地址才会放入元素 push(&S,1); push(&S,2); push(&S,3); push(&S,4); push(&S,5); push(&S,6); traverse(&S); clear(&S); //清空以后就会提示出栈失败 if(pop(&S,&val))//须要判断是否为空,若是空了就没法出栈,因此须要一个返回值,可是进栈不会满的。 { printf("出栈成功,出栈的元素是%d\n",val); } else { printf("出栈失败!\n"); } traverse(&S); return 0; }
全部的算法已经给出,值得注意的是在clear()
算法中 PNODE p = pS->pTop;PNODE q = NULL;
定义了两个指针,觉得一个被free掉后就没法进行操做了,对于pop()
函数就没有这个问题,由于它只执行了一次 ,也就是说,只进行了一次出栈操做,而后操做完成以后才把r指针给free掉的,因此一个指针就能够完成这个操做。
数组
队列是另一种限定性的线性表,它只容许在表的一端插入元素,在另一端删除元素。数据结构
/* 队列的常见操做: 1.初始化队列 2.元素进队列 3.元素出队列 4.队列的遍历 */ #include <stdio.h> #include <stdlib.h> typedef struct Node { int date; struct Node * pNext; }NODE, * PNODE;//LInkQueueNode typedef struct LinkQueue { PNODE pFront; PNODE pRear; }LINKQUEUE,* PLINKQUEUE; bool InitQueue(PLINKQUEUE pQ) { pQ->pFront= (PNODE)malloc(sizeof(NODE)); if (NULL == pQ->pFront) { printf("动态内存分配失败!"); exit(-1); } else if(NULL != pQ->pFront) { pQ->pRear = pQ->pFront; pQ->pFront->pNext = NULL; return (true); } else return (false);//溢出 } bool EnterQueue(PLINKQUEUE pQ ,int x) { PNODE pNew = (PNODE)malloc(sizeof(NODE)); if(pNew != NULL) { pNew->date = x; pNew->pNext = NULL; pQ->pRear->pNext = pNew; pQ->pRear = pNew; return (true); } else return false; } void traverse(PLINKQUEUE pQ) { PNODE p = pQ->pFront->pNext;//注意这个地方队列和栈的不一样 //PNODE p = pS->pTop; while (p != pS->pBottom) 这是栈的条件 while (p) { printf("%d ",p->date); p = p->pNext; } printf("\n"); return; } bool DeleteQueue(PLINKQUEUE pQ,int * x) //出队 { PNODE p; if (pQ->pRear==NULL) //队列为空 return false; p=pQ->pFront; //p指向第一个数据节点 if (pQ->pFront==pQ->pRear) //队列中只有一个节点时 pQ->pFront=pQ->pRear=NULL;//必需要更改值,否则指针就会指向他处 else //队列中有多个节点时 pQ->pFront=pQ->pFront->pNext; *x = p->date; free(p); return true; } int main() { LINKQUEUE Q; int x; InitQueue(&Q); EnterQueue(&Q,10); EnterQueue(&Q,20); EnterQueue(&Q,30); EnterQueue(&Q,40); traverse(&Q); DeleteQueue(&Q,&x); traverse(&Q); return 0; }
队列的操做和栈的操做基本原理上是差很少的,值得注意的是再对队列进行遍历的话和栈的遍历稍微有点差异。其中须要注意的地方已经在代码块中进行了说明。函数
/* 1.循环队列初始化 2.循环队列进队 3.循环队列出队 4.循环队列遍历 5.循环队列长度 */ // 实现循环队列 #include <stdio.h> #include <stdlib.h> #define MaxSize 21 typedef int ElementType; typedef struct { int data[MaxSize]; int rear; // 队尾指针 int front; // 队头指针 }Queue,*L; void InitQueue(Queue * Q ) { Q->front = Q->rear = 0; } // 元素入队 void AddQ(Queue *PtrQ, int item) { if( (PtrQ->rear+1)%MaxSize == PtrQ->front ) { printf("队列满.\n"); return; } PtrQ->rear = (PtrQ->rear+1) % MaxSize; PtrQ->data[PtrQ->rear] = item; } // 删除队头元素并把队头元素返回 int DeleteQ( Queue *PtrQ ) { if( PtrQ->front == PtrQ->rear ) { printf("队列空.\n"); return -1; } else { PtrQ->front = (PtrQ->front+1) % MaxSize; return PtrQ->data[PtrQ->front]; } } // 队列元素的遍历 void print(Queue *PtrQ) { int i = PtrQ->front; if( PtrQ->front == PtrQ->rear ) { printf("队列空."); return; } printf("队列存在的元素以下:"); while( i != PtrQ->rear) { printf("%d ", PtrQ->data[i+1]); i++; i = i % MaxSize; } return; } int len(Queue *PtrQ) { return (PtrQ->rear-PtrQ->front+MaxSize)%MaxSize; } int main() { Queue Q; //注意不是Queue * Q; 由于数组自己就是地址吧~(emmmm,应该是,求大佬解答) int length; length = len(&Q); //用Queue * Q 的话会报错 InitQueue(&Q); AddQ(&Q,1); AddQ(&Q,2); AddQ(&Q,3); AddQ(&Q,4); print(&Q); DeleteQ(&Q);//出队一次 print(&Q); printf("\n循环队列的长度为%d",length); return 0; }
循环队列和链队列基本是一致的,之因此引入“循环队列”是由于,对于顺序列会存在“假溢出的现象”。相关概念很少作解释,原理主要在数据结构-用C语言描述(第二版)[耿国华] 一书的p101-103。值得注意的是,在main
方法中和链队列不一样的是Queue Q;
我的认为是利用数组模拟的缘由,由于数组自己也是利用地址传值嘛。关于循环队列长度计算:当rear大于front时,循环队列的长度:rear-front,当rear小于front时,循环队列的长度:分为两类计算 0+rear和Quesize-front即rear-front+Quesize。总的来讲,总长度是(rear-front+Quesize)%Quesize.net
带头结点的循环链表表示队列, 而且只设一个指针指向队尾元素结点, 试编写相应的队列初始化,入队列和出队列的算法。指针
/* 数据结构算法题(假设以带头结点的循环链表表示队列, * 而且只设一个指针指向队尾元素结点(注意不设头指针) * 试编写相应的队列初始化,入队列和出队列的算法!) */ #include<stdio.h> #include<stdlib.h> #include<time.h> #define OK 1 #define ERROR 0 typedef int QElemType; typedef int Status; typedef struct QNode { QElemType data; struct QNode * rear; struct QNode * next; }QNode,*LinkQueue; //链式队列的初始化 Status InitLinkQueue(LinkQueue * L) { (*L)=(LinkQueue)malloc(sizeof(QNode)); if((*L)==NULL) { printf("内存分配失败!\n"); return OK; } (*L)->rear=(*L); return OK; } //链式队列的创建 Status Create(LinkQueue * L,int n) { srand(time(0)); LinkQueue P; for(int i=0;i<n;i++) { P=(LinkQueue)malloc(sizeof(QNode)); P->data=rand()%100+1; (*L)->rear->next=P; (*L)->rear=P; } P->next=(*L); return OK; } //入队操做 Status EnQueue(LinkQueue * L,QElemType e) { LinkQueue P; P=(LinkQueue)malloc(sizeof(QNode)); P->data=e; P->next=(*L); (*L)->rear->next=P; (*L)->rear=P; return OK; } //出队操做 Status DeQueue(LinkQueue * L,QElemType * e) { LinkQueue temp; *e=(*L)->next->data; temp=(*L)->next; (*L)->next=(*L)->next->next; delete(temp); return OK; } //输出 void Print(LinkQueue * L) { LinkQueue P; P=(*L)->next; printf("输出元素:\n"); while(P!=(*L)) { printf("%d ",P->data); P=P->next; } printf("\n"); } int main() { LinkQueue L; int ElemNumber; QElemType EnElem,DeElem; InitLinkQueue(&L); printf("请输入元素个数:\n"); scanf("%d",&ElemNumber); Create(&L,ElemNumber); Print(&L); printf("请输入入队元素:\n"); scanf("%d",&EnElem); EnQueue(&L,EnElem); Print(&L); printf("出队操做,并返回出队元素:\n"); DeQueue(&L,&DeElem); printf("出队元素为:%d\n",DeElem); Print(&L); return 0; }