线性表栈和队列Word下载.docx
《线性表栈和队列Word下载.docx》由会员分享,可在线阅读,更多相关《线性表栈和队列Word下载.docx(27页珍藏版)》请在冰豆网上搜索。
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>
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<
=l.numinlist||l.numinlist==0)
47exit(0);
48temp=l.element[i];
49for(j=i;
j<
l.numinlist-1;
j++)
50l.element[j]=l.element[j+1];
51l.numinlist--;
52returntemp;
53}
54
55intsearch(ELEMTYPEitem)
56{
57inti;
58for(i=0;
i<
l.numinlist;
i++)
59if(l.element[i]==item)
60returni;
61return-1;
62}
63
64voidtraversal()
65{
66inti;
67for(i=0;
l.numinlist;
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
20
101530
单链表基本操作的实现
在线性表的顺序表示中,由于逻辑上相邻的两个元素在物理位置上也相邻,则每个元素的存储地址都可从线性表的起始地址计算得到。
而在单链表中,任何两个元素的存储地址之间没有固定的联系,表中每个元素的存储地址都包含在其前驱结点的指针域中,所以,单链表的运算与顺序表的运算一般有所不同。
设head和tail分别为带表头结点的单链表的头指针和尾指针。
图2.6给出了单链表基本操作的实现。
1#include<
alloc.h>
3structnode{
4ELEMTYPEelement;
5structnode*next;
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;
24intlength()
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->
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->
51q=head;
52j=1;
53while((q!
=NULL)&
&
(j<
i)){
54q=q->
55j++;
56}
57if((!
q)||(j>
i))exit(0);
58ltemp->
next=q->
59q->
next=ltemp;
60if(tail==q)tail=ltemp;
61}
62
63ELEMTYPEdel(inti)
64{
65structnode*p,*q;
66ELEMTYPEtemp;
67intj;
68q=head;
69p=head->
70j=1;
71while((p!
72q=p;
73p=p->
74j++;
75}
76if((!
p)||(j>
i))exit(0);
77temp=p->
element;
78q->
next=p->
79if(tail==p)tail=q;
80free(p);
81returntemp;
82}
83
84structnode*search(ELEMTYPEitem)
85{
86structnode*p;
87p=head->
88while(p!
=NULL){
89if(p->
element==item)
90returnp;
91else
92p=p->
93}
94returnNULL;
95}
96
97structnode*get(inti)
98{
99structnode*p;
100intj;
101p=head->
102for(j=1;
(p!
i);
103p=p->
104if((!
i))returnNULL;
105returnp;
106}
107
108voidtraversal()
109{
110structnode*p;
111printf("
listis:
"
112for(p=head->
113printf("
p->
element);
114printf("
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("
del
(2));
133traversal();
134
135p=search(30);
136if(!
p)
137printf("
\nNotfind!
138else
139printf("
\n%d"
140
141p=get(3);
142if(!
143printf("
144else
145printf("
147}
图2.6单链表的基本操作的实现
图2.6所示单链表基本操作的输出内容为:
Listis:
10203040
Lengthis:
4
1035203040
35
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->
(或者ltemp->
)
q->
函数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->
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函数输出栈顶元素。
stdlib.h>
2#include<
malloc.h>
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