线性表栈和队列.docx
- 文档编号:5092079
- 上传时间:2022-12-13
- 格式:DOCX
- 页数:27
- 大小:35.20KB
线性表栈和队列.docx
《线性表栈和队列.docx》由会员分享,可在线阅读,更多相关《线性表栈和队列.docx(27页珍藏版)》请在冰豆网上搜索。
线性表栈和队列
顺序表基本操作的实现
使用顺序存储结构,线性表的某些操作很容易实现。
图2.1给出了采用顺序存储结构的线性表部分操作的实现。
第1行定义了一个常数值MAXSIZE,表示线性表的最大长度,示例中将其设为999。
第2行把ELEMTYPE设置为int的一个别名,这样,这个例子就可以使用一组整数了。
第3行到第7行包含了线性表的说明。
接下来从第8行到第70行是线性表操作函数的实现。
第9到第12行完成将线性表置成空表操作。
将线性表置成空表,只需简单地将线性表元素个数置成0(numinlist=0)即可。
函数isEmpty(第14行到第17行)判断线性表是否为空,如果线性表为空(没有元素),函数返回1,否则返回0。
函数length(第19行到第22行)返回线性表中元素个数。
由于线性表的长度已经记录在变量numinlist中,因此函数length只是简单返回numinlist的值。
第24到第29行实现追加操作。
函数append完成在线性表的表尾插入一个元素。
函数首先检查线性表是否已满(第26行),如果线性表已满,程序结束,否则即可将新元素插入到表尾位置,并将线性表长度增1,插入位置由numinlist指示。
第31行到第40行的函数insert完成线性表的插入操作。
在线性表中第i位置插入一个新元素item时,函数首先判断插入位置是否合法,以及表是否已满,如果插入位置不合法或表已满,程序结束。
否则通过for循环将最后一个元素到第i个元素逐个向后移动,最后将item插入到第i个位置,且线性表的长度加1。
第42行到第53行完成删除元素操作。
函数首先判断删除位置i是否合法,或表中是否有元素,如果删除位置不合法或表为空表,程序结束。
否则先将被删除元素的值保存在临时变量temp中,然后通过一个for循环将被删除元素到最后一个元素逐个向前移动,最后将表的长度减1,并将被删除元素的值返回。
第55行到第62行的函数search在线性表中搜寻第一个出现的值为item的元素。
如果值item找到了,函数返回元素item所在位置,否则返回-1,表示线性表中不存在元素item。
函数traversal(第64行到第70行)对线性表进行遍历。
遍历操作只是通过一个for循环将表中元素逐个输出。
第72行到第87行是main函数的一个例子,说明了线性表的顺序表实现。
74行调用init函数将线性表清空,第75,76,77三行调用append函数追加三个元素。
insert(2,15)(79行)在位置2插入一个元素15。
81的search(15)在表中查找元素15。
第85行调用del函数删除位置1的元素。
1#defineMAXSIZE999
2typedefintELEMTYPE;
3structlist{
4ELEMTYPEelement[MAXSIZE];
5intnuminlist;
6};
7structlistl;
8
9voidinit()
10{
11l.numinlist=0;
12}
13
14intisEmpty()
15{
16return(l.numinlist==0);
17}
18
19intlength()
20{
21returnl.numinlist;
22}
23
24voidappend(ELEMTYPEitem)
25{
26if(l.numinlist>MAXSIZE)
27exit(0);
28l.element[l.numinlist++]=item;
29}
30
31voidinsert(inti,ELEMTYPEitem)
32{
33intj;
34if(i<0||i>l.numinlist||l.numinlist>MAXSIZE)
35exit(0);
36for(j=l.numinlist;j>i;j--)
37l.element[j]=l.element[j-1];
38l.element[i]=item;
39l.numinlist++;
40}
41
42ELEMTYPEdel(inti)
43{
44intj;
45ELEMTYPEtemp;
46if(i<0||i>=l.numinlist||l.numinlist==0)
47exit(0);
48temp=l.element[i];
49for(j=i;j 50l.element[j]=l.element[j+1]; 51l.numinlist--; 52returntemp; 53} 54 55intsearch(ELEMTYPEitem) 56{ 57inti; 58for(i=0;i 59if(l.element[i]==item) 60returni; 61return-1; 62} 63 64voidtraversal() 65{ 66inti; 67for(i=0;i 68printf("%d",l.element[i]); 69printf("\n"); 70} 71 72voidmain() 73{ 74init(); 75append(10);/*Lis(10)*/ 76append(20);/*Lis(10,20)*/ 77append(30);/*Lis(10,20,30)*/ 78traversal();/*Lis(10,20,30)*/ 79insert(2,15);/*Lis(10,20,15,30)*/ 80traversal(); 81if(search(15)! =-1) 82printf("element15isinlist! "); 83else 84printf("element15isnotinlist! "); 85printf("\n%d\n",del (1)); 86traversal();/*Lis(10,15,30)*/ 87} 图2.1顺序表表示法的线性表操作的实现 图2.1所示程序的输出结果为: 102030 10201530 element15isinlist! 20 101530 单链表基本操作的实现 在线性表的顺序表示中,由于逻辑上相邻的两个元素在物理位置上也相邻,则每个元素的存储地址都可从线性表的起始地址计算得到。 而在单链表中,任何两个元素的存储地址之间没有固定的联系,表中每个元素的存储地址都包含在其前驱结点的指针域中,所以,单链表的运算与顺序表的运算一般有所不同。 设head和tail分别为带表头结点的单链表的头指针和尾指针。 图2.6给出了单链表基本操作的实现。 1#include 2typedefintELEMTYPE; 3structnode{ 4ELEMTYPEelement; 5structnode*next; 6}; 7structnode*head; 8structnode*tail; 9 10voidinit() 11{ 12head=(structnode*)malloc(sizeof(structnode)); 13if(! head)exit(0); 14head->next=NULL; 15tail=head; 16} 17 18intisEmpty() 19{ 20if(head==tail)return1; 21elsereturn0; 22} 23 24intlength() 25{ 26structnode*p; 27intcnt=0; 28for(p=head->next;p! =NULL;p=p->next) 29cnt++; 30returncnt; 31} 32 33voidappend(ELEMTYPEitem) 34{ 35structnode*p; 36p=(structnode*)malloc(sizeof(structnode)); 37if(! p)exit(0); 38p->element=item; 39p->next=tail->next; 40tail->next=p; 41tail=p; 42} 43 44intinsert(inti,ELEMTYPEitem) 45{ 46structnode*q,*ltemp; 47intj; 48ltemp=(structnode*)malloc(sizeof(structnode)); 49if(! ltemp)exit(0); 50ltemp->element=item; 51q=head; 52j=1; 53while((q! =NULL)&&(j 54q=q->next; 55j++; 56} 57if((! q)||(j>i))exit(0); 58ltemp->next=q->next; 59q->next=ltemp; 60if(tail==q)tail=ltemp; 61} 62 63ELEMTYPEdel(inti) 64{ 65structnode*p,*q; 66ELEMTYPEtemp; 67intj; 68q=head; 69p=head->next; 70j=1; 71while((p! =NULL)&&(j 72q=p; 73p=p->next; 74j++; 75} 76if((! p)||(j>i))exit(0); 77temp=p->element; 78q->next=p->next; 79if(tail==p)tail=q; 80free(p); 81returntemp; 82} 83 84structnode*search(ELEMTYPEitem) 85{ 86structnode*p; 87p=head->next; 88while(p! =NULL){ 89if(p->element==item) 90returnp; 91else 92p=p->next; 93} 94returnNULL; 95} 96 97structnode*get(inti) 98{ 99structnode*p; 100intj; 101p=head->next; 102for(j=1;(p! =NULL)&&(j 103p=p->next; 104if((! p)||(j>i))returnNULL; 105returnp; 106} 107 108voidtraversal() 109{ 110structnode*p; 111printf("listis: "); 112for(p=head->next;p! =NULL;p=p->next) 113printf("%d",p->element); 114printf("\n"); 115} 116 117voidmain() 118{ 119structnode*p; 120 121init(); 122append(10);/*listis10*/ 123append(20);/*listis1020*/ 124append(30);/*listis102030*/ 125append(40);/*listis10203040*/ 126traversal(); 127printf("lengthis: %d\n",length()); 128 129insert(2,35); 130traversal();/*listis1035203040*/ 131 132printf("\n%d\n",del (2)); 133traversal();/*listis10203040*/ 134 135p=search(30); 136if(! p) 137printf("\nNotfind! "); 138else 139printf("\n%d",p->element); 140 141p=get(3); 142if(! p) 143printf("\nNotfind! "); 144else 145printf("\n%d",p->element); 147} 图2.6单链表的基本操作的实现 图2.6所示单链表基本操作的输出内容为: Listis: 10203040 Lengthis: 4 Listis: 1035203040 35 Listis: 10203040 30 30 在图2.6中,第2行把ELEMTYPE设置为int的一个别名,这样,这个单链表中结点的元素值就为整数了。 第3行到第8行包含了线性表的说明,其中element用来存放结点的数据信息,next为指针域,指明结点的唯一后继结点在内存中的存放地址。 head和tail分别表示单链表的头指针和尾指针。 接下来从第10行到第115行是线性表运算函数的定义。 函数init(第10行到第16行)实现单链表的初始化。 函数首先通过C语言提供的malloc函数申请一个结点作为表头结点,并由头指针head指向,如果申请空间失败,程序结束。 否则将该结点的next置成空(NULL),然后将尾指针tail也指向该表头结点。 函数isEmpty(第18行到第22行)判断单链表是否为空,如果头指针head和尾指针tail相等,则表示单链表为空,说明表中无元素。 函数返回1,否则,函数返回0。 函数length(第24行到第31行)统计单链表中结点的数目。 函数通过一个for循环从第一个结点开始(p=head->next)计数,如果不是最后一个结点(p! =NULL),计数器cnt就加1,然后到下一个结点(p=p->next),直到最后一个结点为止。 计数器cnt的值就是单链表的结点个数。 第33行到第42行的函数append实现在单链表的最后追加一个新结点,新结点的元素值为item。 函数首先申请一个空结点(第36行),如果申请失败,程序结束。 否则将item和NULL分别填入该结点的element域和next域。 然后将新结点链入单链表中(第39行和第40行),最后将单链表尾指针tail指向新结点,使其成为新的最后结点(tail=p)。 设p是指向单链表结点的指针,在p指向的结点前面插入一个结点包括三个步骤。 首先,要创建一个新结点,并且赋给它一个值。 其次,新结点的next指向指针p指向的结点。 第三,指针p指向的结点的前趋结点的next指向新插入的结点。 图2.7给出了这三个步骤的图示。 (a)插入前的链表(b)插入后的链表 图2.7在单链表中插入一个结点的过程 假设ltemp为指向新插入结点的指针,指针q指向p结点的前趋结点,则上述指针修改的代码为 ltemp->next=p;(或者ltemp->next=q->next;) q->next=ltemp; 函数insert(第44行到第61行)实现了上述过程。 该函数在单链表的第i个结点前插入一个新结点,item为新结点的元素值。 算法在实现时,首先申请一个结点,指针ltemp指向该结点(48行)。 如果申请失败,则程序结束(49行)。 否则用item初始化该结点element域(50行)。 接着从表头开始(q=head),通过while循环定位新结点插入位置(53行到56行)。 如果插入位置不合法,程序结束(57行)。 否则指针q停留在被插入位置的前趋结点,最后根据上面所述修改相应指针。 如果是在最后结点后插入结点,还需要修改尾指针,使其指向新插入结点(60行)。 从单链表删去一个结点很简单,只需将被删结点的前趋结点的next域指向被删结点的后继结点即可。 图2.8给出了删除一个结点的指针变化情况。 但必须注意,被删结点占据的内存空间应该返还给存储器,可调用C语言提供的标准函数free将被删去结点所占据的内存空间返还给存储器。 (a)删除值为12的结点前的单链表 (b)删去结点后指针的变化情况 图2.8删去一个结点的过程 设指针q为被删除结点p的前驱结点指针,删除结点p的代码为: q->next=p->next; free(p); 实现上述过程的代码包含在函数del中(第63行到第82行)。 指针p被用来指向被删除结点,指针q被用来指向被删除结点的前趋结点,temp用来存放被删除结点的元素值。 算法首先从表头开始寻找被删除结点的前趋结点,如果没有找到被删除的结点,则程序结束。 否则,将被删除结点的元素值保存到临时变量temp中(77行),并修改相应指针(78行)。 如果被删除的结点是最后一个结点,还需要将尾指针指向被删除结点的前趋(79行)。 第80行归还被删结点所占据的存储空间,81行返回被删除结点的元素值。 在单链表中查找特定值(item)的元素过程由函数search完成(84行到95行)。 函数首先从表头开始(87行),通过一个while循环实现查找过程。 如果表中还有元素(p! =NULL),则判断该元素是否是要查找的元素,如果是,则返回该元素地址,否则到下一个结点(92行)。 如果表中没有要找的元素,函数返回NULL。 由于单链表中任何两个元素的存储位置之间没有固定的联系,每个元素的存储位置只能通过其前趋结点得到。 因此,在单链表中寻找第i个结点就不像顺序表那么容易。 在单链表中,取得第i个元素必须从单链表头结点出发寻找。 函数get(第97行到第106行)从链表表头结点开始寻找第i个结点,若结点i不存在,函数返回空(NULL),否则返回指向该结点的指针。 单链表的遍历和顺序表的遍历非常相似,顺序表使用下标值,而链表则是使用指针来处理每个结点。 最大的不同在于顺序表可以随机存取元素,可是链表结构一定要用遍历的方式来存取其中的每一个结点。 因为头指针只能获得第一个结点的内容,如果要知道第i个结点的内容,一定要遍历到第i-1个结点才能知道它的地址。 函数traversal(第108行到第115行)实现链表的遍历。 在循环的开始,首先将指针p指向第一个结点,接着进入循环,循环的条件是测试指针p是否已指向链表的结尾。 因为链表的最后一个结点的指针会指向NULL,所以当指针指向NULL时,表示已经走到了链表的最后。 而在循环中的语句p=p->next就是移动指针指向下一个结点。 第117行到第147行是main函数,说明了线性表的链式存储结构下操作函数的使用。 121行调用init函数将链表置成空表。 第122到125的四行调用append函数追加四个元素,此时线性表为(10,20,30,40)。 127行输出线性表的长度(此时输出4)。 insert(2,35)(129行)在位置2插入一个元素35,线性表变为(10,35,20,30,40)。 132行输出被删除的第2个结点的值(35)。 135行在表中查找元素30。 第141行调用get函数定位第3个元素。 顺序栈 在图3.2中,第3行定义了一个常数值MAXSIZE,这是因为数组的大小需要提前声明。 在顺序栈的实现中,MAXSIZE表示栈的最大长度,示例中将其设为999。 第4行把ELEMTYPE设置为char的一个别名,这样,这个示例栈就可以使用一组字符了。 第5行到第9行包含了顺序栈的定义,s为顺序栈。 接下来从第11行到第64行是顺序栈操作函数的实现。 第11到第14行完成栈的初始化。 顺序栈的初始化很简单,只需将栈顶指针top置为0即可。 函数EmptyStack(第16行到第19行)判断顺序栈是否为空,如果为空(没有元素),函数返回1,否则返回0。 第21到第31行实现入栈操作。 进栈函数PushStack完成在顺序栈的栈顶插入一个元素。 函数首先检查顺序栈是否已满,如果已满,程序结束,否则将新元素插入到栈顶位置,并移动栈顶指针。 第33行到第43行完成出栈操作。 出栈函数PopStack首先判断栈中是否有元素,如果为空栈(意味着没有元素),程序结束。 否则先移动栈顶指针,然后将栈顶元素的值返回。 注意,出栈操作,需要先判栈是否为空,为空时不能操作,否则产生错误。 通常栈空时常作为一种控制转移的条件。 第45行到第53行的函数TopStack实现取栈顶元素,如果栈为空,则退出程序,否则返回栈顶元素的值。 取栈顶元素操作与出栈操作类似,不同的是出栈操作需要修改栈顶指针,而取栈顶元素操作不需要修改栈顶指针。 函数LengthStack(第55到第58行)返回顺序栈中元素个数。 由于栈顶指针记录的就是栈中元素个数,因此函数只是简单返回top的值。 第60行到第71行说明了顺序栈的应用。 62行调用InitStack函数建立一个空栈,第63到第67行调用PushStack函数将五个字符元素入栈。 第68行调用LengthStack函数输出栈中元素个数,第69行调用PopStack函数删除栈顶元素。 第70行调用TopStack函数输出栈顶元素。 1#include 2#include 3#defineMAXSIZE999 4typedefcharELEMTYPE; 5structSeqStack{ 6ELEMTYPEelement[MAXSIZE]; 7inttop; 8}; 9structSeqStacks; 10 11voidInitStack() 12{ 13s.top=0; 14} 15 16intEmptyStack() 17{ 18return(s.top==0); 19} 20 21voidPushSta
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 线性 队列