知ing

数据结构实用教程(第二版)

徐孝凯 编 / 清华大学出版社

谁南 上传

查看本书

1.

⑴解:(79,62,34,57,26,48)

⑵解:(26,34,48,57,62,79)

⑶解:(48,56,57,62,79,34)

⑷解:(56,57,79,34)

⑸解:(26,34,39,48,57,62)

2.

解:

为了排版方便,假定采用以下输出格式表示单链接表的示意图;每个括号内的数据表示一个元

素结点,其中第一个数据为元素值,第二个数据为后继结点的指针,第一个元素结点前的数值为

表头指针。

⒈(7(79,6),(62,5),(34,4),(57,3),(26,2),(48,0))

⒉(3(26,5),(34,2),(48,4),(57,6),(62,7),(79,0))

⒊(2(48,8),(56,4),(57,6),(62,7),(79,5),(34,0))

⒋(8(56,4),(57,7),(79,5),(34,0))

3.对于List类型的线性表,编写出下列每个算法。

⑴ 从线性表中删除具有最小值的元素并由函数返回,空出的位置由最后一个元素填补,若

线性表为空则显示出错信息并退出运行。

解: ElemType DMValue(List&L)

//从线性表中删除具有最小值的元素并由函数返回,空出的位置

//由最后一个元素填补,若线性表为空则显示出错信息并退出运行

{

if(ListEmpty(L)){

cerr<<"List is Empty!"<<end1;

exit(1);

}

ElemType x;

x=L.list[0];

int k=0;

for(int i=1;i<L.size;i++){

ElemType y=L.list[i];

if(y<x){x=y;k=i;}

}

L.list[k]=L.list[L.size-1];

L.size--;

return x;

}

⑵ 从线性表中删除第i个元素并由函数返回。

解:int Deletel(List& L,int i)

//从线性表中删除第i个元素并由函数返回

{

if(i<1||i>L.size){

cerr<<"Index is out range!"<<end1;

exit(1);

}

ElemType x;

x=L.list[i-1];

for(int j=i-1;j<L.size-1;j++)

L.list[j]=L.list[j+1];

L.size--;

return x;

}

⑶ 向线性表中第i个元素位置插入一个元素。

解:void Inser1(List& L,int i,ElemType x)

//向线性表中第i个元素位置插入一个元素

{

if(i<1||i>L.size+1){

cerr<<"Index is out range!"<<end1;

exit(1);

}

if(L.size==MaxSize)

{

cerr<<"List overflow!"<<end1;

exit(1);

}

for(int j=L.size-1;j>i-1;j--)

L.list[j+1]=L.list[j];

L.list[i-1]=x;

L.size++;

}

⑷ 从线性表中删除具有给定值x的所有元素。

解:void Delete2(List& L,ElemType x)

//从线性表中删除具有给定值x的所有元素

{

int i=0;

while(i<L.size)

if(L.list[i]==x){

for(int j=i+1;j<L.sizr;j++)

L.list[j-1]=L.list[j];

L.size--;

}

else

i++;

}

⑸ 从线性表中删除其值在给定值s和t之间(要求s小于t)的所有元素。

解:void Delete3(List& L,ElemType s,ElemType t)

//从线性表中删除其值在给定值s和t之间的所有元素

{

int i=0;

while(i<L.size)

if((L.list[i]>=s)&&(L.list[i]<=t)){

for(int j=i+1;j<L.size;j++)

L.list[j-i]=L.list[j];

L.size--;

}

else

i++;

}

⑹ 从有序表中删除其值在给定值s和t之间(要求s小于t)的所有元素。

解:void Delete4(List& L,ElemType s,ElemType t)

//从有序表中删除其值在给定值s和t之间的所有元素

{

int i=0;

while(i<L.size)//从有序表L中查找出大于等于s的第一个元素

if(L.list[i]<s)i++;

else break;

if(i<L.size){

While((i+j<L.size)&&(L.list[i+j]<=t))

j++;//求出s和t之间元素的个数

for(int k=i+j;k<L.size;k++)

L.list[k-j]=L.list[k];

L.size-=j;

}

}

⑺ 将两个有序表合并成一个新的有序表并由变量返回。

解:void Merge(List& L1,List& L2,List& L3)

//将两个有序表合并成一个新的有序表并由变量返回

{

if(L1.size+L2.size>MaxSize){

cerr<<"List overflow!"<<end1;

exit(1);

}

int i=0,j=0,k=0;

while((i<L1.size)&&(j<L2.size)){

if(L1.list[i]<=L2.list[j])

{ //将L1中的元素赋给L

L.list[k]=L1.list[i];

i++;

}

else{ //将L2中的元素赋给L

L.list[k]=L2.list[j];

j++;

}

k++;

}

while(i<L1.size){ //将L1中剩余的元素赋给L

L.list[k]=L1.list[i];

i++;k++;

}

while(j<L2.size){ //将L2中剩余的元素赋给L

L.list[k]=L2.list[j];

j++;k++;

}

L.size=k;

}

⑻ 从线性表中删除所有其值重复的元素,使其所有元素的值均不同,如对于线性表(2,8,9,

2,5,5,6,8,7,2),则执行此算法后变为(2,8,9,5,6,7)。

解:void Delete5(List& L)

//从线性表中删除所有其值重复的元素,使其所有元素的值均不同

{

int i=0;

while(i<L.size){

int j=i+1;

while(j<L.size)

{ //删除重复值为L.list[i]的所有元素

if(L.list[j]==L.list[i]){

for(int k=j+1;k<L.size;k++)

L.list[k-1]=L.list[k];

L.size--;

}

else

j++;

}

i++;

}

}

4.对于结点类型为LNode的单链接表,编写出下列每个算法。

⑴ 将一个单链接表按逆序链接,即若原单链表中存储元素的次序为a1,a2,...,an,则

逆序链接后变为an,an-1,...a1。

解:void Contrary(LNode*&HL)

//将一个单多办实事有按逆序链接

{

LNode*p=HL;//p指向待逆序的第一个结点,初始指向原表头结点

HL=NULL;//HL仍为逆序后的表头指针,禄始值为空

while(p!=NULL)

{ //把原单链表中的结点依次进行逆序链接

LNode*q=p; //q指向待处理的结点

p=p->next; //p指向下一个待逆序的结点

//将q结点插入到已陈序单链表的表头

q->next=HL;

HL=q;

}

}

⑵ 删除单链表中的第i个结点。

解:void Delete1(LNode*&HL,int i)

//删除单链表中的第i个结点

{

if(i<1||HL==NULL){

cerr<<"Index is out range!"<<end1;

exit(1);

}

LNode*ap,*cp;

ap=NULL;cp=HL; //cp指向当前结点,ap指向其前驱结点

int j=1;

while(cp!=NULL)

if(j==i)

break; //cp结点即为第i个结点

else{ //继续向后寻找

ap=cp;

cp=cp->next;

j++;

}

if(cp==NULL){

cerr<<"Index is out range!"<<end1;

exit(1);

}

if(ap==NULL)

HL=HL->next;

else

ap->next=cp->next;

delete cp;

}

⑶ 从单链表中查找出所有元素的最大值,该值由函数返回,若单链表为空,则显示出错信息

并停止运行。

解:ElemType MaxValue(LNode*HL)

//从单链表中查找出所有元素的最大值,该值由函数返回

{

if(HL==NULL){

cerr<<"Linked list is empty!"<<end1;

exit(1);

}

ElemType max=HL->data;

LNode*p=HL->next;

while(p!=NULL){

if(max<p->data) max=p->data;

p=p->next;

}

return max;

}

⑷ 统计出单链表中结点的值等于给定值x的结点数。

解:int Count(LNode*HL,ElemType x)

//统计出单链表中结点的值等于给定值x的结点数

{

int n=0;

while(HL!=NULL){

if(HL->data==x) n++;

HL=HL->next;

}

return n;

}

⑸ 根据一维数组a[n]建立一个单链表,使单链表中元素的次序与a[n]中元素的次序相同,

并使该算法的时间复杂度为O(n)。

解:void Create(LNode*&HL,ElemType a[],int n)

//根据一维数组a[n]建立一个单链表

{

InitList(HL);

for(int i=n-1;i>=0;i--)

InsertFront(HL,a[i];

}

⑹ 将一个单链表重新链接成有序单链表。

解:void OrderList(LNode*&HL)

//将一个单链表重新链接成有序单链表

{

LNode* p=HL;//p指向待处理的第一个结点,初始指向原表头结点

HL=NULL; //HL仍为待建立的有序表的表头指针,禄始值为空

while(p!=NULL)

{ //把原单链表中的结点依次进行有序链接

LNode* q=p; //q指向待处理的结点

p=p->next; //p指向下一个待处理的结点

LNode* ap=NULL,*cp=HL;

//cp指向有序表中待比较的结点,ap指向其前驱结点

while(cp!=NULL)

{ //为插入q结点寻找插入位置

if(q->data<cp->data)

break;

else{

ap=cp;

cp=cp->next;

}

} //将q结点插入到ap和cpxf hko pp uj

q->next=cp;

if(ap==NULL)

HL=q;

else

ap->next=q;

}

}

⑺ 将两个有序单链表合并成一个有序单链表,合并后使原有单链表为空。

解:LNode*Mergel(LNode*&p1,LNode*&p2)

//将两个有序单链表合并成一个有序单链表

{

LNode a; //a结点作为结果的有序单链表的表头附加结点,这样便于处理,处理

//结束后返回a结点的镄针域的值

LNode*p=&a; //p指向结果的有序单链表的表尾结点

p->next=NULL;//初始指向表头附加结点

while((p1!=NULL)&&(p2!=NULL))

{//处理两个表非空的情况

if(p1->data<p2->data){

p->next=p1;p1=p1->next;

}

else{

p->next=p2;p2=p2->;

}

p=p->next;

}

if(p1!=NULL)p->next=p1;

if(p2!=NULL)p->next=p2;

p1=p2=NULL;

return a.next;

}

⑻ 根据两个有序单链表生成一个新的有序单链表,原有单链表保持不变。如假定两个有序单链

表中的元素为(2,8,10,20)和(3,8,9,15,16),则生成的新单链表中的元素为(2,3,8,8,9,10,15,

16,20)。

解:LNode*Merge2(LNode*p1,LNode*p2)

//根据两个有序单链表生成一个新的有序单链表

{

LNode a; //用a作为新的有序单链表的表头附加结点

LNode*p=&a; //p指向结果有序单链表的表尾结点

p->next=NULL; //初始指向表头附加结点

while((p1!=NULL&&(p2!=NULL))

{ //处理两个表非空时的情况

LNode*newptr=new LNode;

if(p1->data<p2->data)

{ //由p1->data建立新结点,然后p1指针后移

newptr->data=p1->data;

p1=p1->next;

}

else

{ //由p2->data建立新结点,然后p2指针后移

newptr->data=p2->data;

p2=p2->next;

}

//将newptr结点插入到结果的有序表的表尾

p->next=newptr;

p=newptr;

}

while(p1!=NULL)

{ //继续处理p1单链表中剩余的结点

LNode*newptr=new LNode;

newptr->data=p1->data;

p1=p1->next;

p->next=newptr;

p=newptr;

}

while(p2!=NULL)

{ //继续处理p2单链表中剩余的结点

LNode*newptr=new LNode;

newptr->data=p2->data;

p2=p2->next;

p->next=newptr;

p=newptr;

}

p->next=NULL;

return a.next;

}

⑼ 根据一个元素类型为整型的单链表生成两个单链表,使得第一个单链表中包含原单链表中所有

元素值为奇数的结点,使得第二个单链表中包含原单链表中所有元素值为偶数的结点。原有单链表

保持不变。

解:void Separate(LNode*HL,LNode*&p1,LNode*&p2)

//根据一个单链表HL按条件拆分生成两个单链表p1和p2

{

LNode a,b; //a和b结点分别作为p1和p2单链表的表头附加结点

LNode*t1=&a,*t2=&b; //t1和t2分别作为指向p1和p2单链表的

//表尾结点,初始指向表头附加结点

Lnode*p=HL;

while(p!=NULL)

{ //每循环一次产生一个新结点,并把它加入到p1或p2单链表

//的未尾

LNode*newptr=new LNode;

if(p->data%2==1){

newptr->data=p->data;

t1->next=newptr;

t1=newptr;

}

else{

newptr->data=p->data;

t2->next=newptr;

t2=newptr;

}

p=p->next;

}

t1->next=t2->next=NULL;

p1=a.next;p2=b.next; //把指向两个单链表的表头结点的指针分别赋给

//p1和p2返回

}

6.编写一个算法,使用表头附加结点的循环单链表解决约瑟夫(Josephus)问题。其问题是

:设有n个人围坐在一张圆桌周围,现从某个人开始从1报数,数到m的人出列(即离开坐位,

不参加以后的报数),接着从出列的下一个人开始重新从1报数,数到m的人又出列,如此下

去直到所有人都出列为止,试求出它们的出列次序。

假如,当n=8、m=4时,若从第一个人(假定每个人的编号依次为1,2...,n)开始报数,则得

到的出列次序为:4,8,5,2,1,3,7,6。

此算法要求以n、m和s(假定从第s个人开始第一次报数)作为值参。

解:

void Josephus(int n,int m,int s)

//使用带表头附加结点的循环单链表解决约瑟夫问题

{

//生成表头附加结点,此时循环单链表为空

LNode*HL=new LNode;

HL->next=HL;

int i;

//生成含有n个结点、结点依次为1,2,...n的带表头结点的循环单链表

for(i=n;i>=1;i--){

//生成新的结点

LNode*newptr=new LNode;

newptr->data=i;

//把新的结点插入到表头

newptr->next=HL->next;

HL->next=newptr;

}

//从表头开始顺序查找出第s个结点,对应第一个开始报数的人

LNode*ap=HL,*cp=HL->next;

for(i=1;i<s;i++){

//ap和cp指针后移一个位置

ap=cp;

cp=cp->next;

//若cp指向了表头附加结点,则仍需后移ap和cp指针,使之指向表头结点

if(cp==HL){ap=HL;cp=HL->next;}

}

//依次使n-1个人出列

for(i=1;i<n;i++){

//顺序查找出待出列的人,即为循环结束后cp所指向的结点

for(int j=1;j<m;j++){

ap=cp;

cp=cp->next;

if(cp==HL){ap=HL;cp=HL->next;}

}

//输出cp结点的值,即出列的人

cout<<cp->data<<"";

//从单链表中删除cp结点

ap->next=cp->next;

delete cp;

//使cp指向被删除结点的后继结点

cp=ap->next;

//若cp指向了表头附加结点,则后移ap和cp指针

if(cp==HL){ap=HL;cp=HL->next;}

}

//使最后一个人出列

cout<<HL->next->data<<end1;

//删除表头结点和表头附加结点

delete HL->next;

delete HL;

}

7.对于在线性表抽象数据类型中定义的每一个操作,写出结点类型为LNode的带头附加结点

的循环单链表上实现的对应算法。

⑴初始化单链表

解:void InitList(LNode*HL)

{

HL->next=HL;//将单链表置空

}

⑵删除单链表中的所有结点,使之成为一个空表

void ClearList(LNode*HL)

{

LNode*cp,*np;

cp=HL->next;//将指向第一个结点的指针赋给cp

while(cp!=HL)//遍历单链表,向系统交回每一个结点。

{

np=cp->next;//保存下一个结点的指针。

delete cp;//删除当前结点。

cp=np;//使下一个结点成为当前结点。

}

HL->next=HL;//置单链表为空

}

⑶得到单链表的长度

int ListSize(LNode*HL)

{

LNode*p=HL->next;

int i=0;

while(p!=HL){i++;p=p->next;}

return i;

}

⑷检查单链表是否为空

int ListEmpty(LNode*hl)

{

return(HL->next==HL);

}

⑸得到单链表中第pos个结点中的元素

ElemType GetElem(LNode*HL,int pos)

{

if(pos<1){

cerr<<"pos is out range!"<<end1;

exit(1);

}

LNode* p=HL->next;

int i=0;

while(p!=HL){

i++;

if(i==pos)break;

p=p->next;

}

if(p!=HL)return p->data;

else{

cerr<<"pos is out range!"<<end1;

exit(1);

}

}

⑹遍历单链表

void TraverseList(LNode*HL)

{

LNode* p=HL->next;

while(p!=HL){

cout<<p->data<<"";

p=p->next;

}

cout<<end1;

}

⑺从单链表查找具有给定值的第一个元素

int Find(LNode* HL,ElemType& item)

{

LNode* p=HL->next;

while(p!=HL)

if(p->data==item){

item=p->data;

return 1;

}

else

p=p->next;

return 0;

}

⑻更新单链表中具有给定值的第一个元素

int Updata(LNode* HL,const ElemType& item)

{

LNode* p=HL->next;

while(p!=HL)//查找元素

if(p->data==item)break;

else p=p->next;

if(p==HL)return 0;

else{//更新元素

p->data=item;

return 1;

}

}

⑼向单链表的未尾插入一个元素

void InsertRear(LNode* HL,const ElemType& item)

{

LNode* newptr;

newptr=new LNode;

newptr->data=item;//把新元素赋给动态结点*newptr的值域。

LNode* p=HL;

while(p->next!=HL)//从表头开始遍历到最后一个结点为止。

p=p->next;

newptr->next=HL;p->next=newptr;//把新结点链接到表尾。

}

⑽向单链表的表头插入一个元素

void InsertFront(LNode* HL,const ElemType& item)

{

LNode* newptr;

newptr=new LNode;

newptr->data=item;

newptr->next=HL->next;

HL->next=newptr;

}

(11)向单链表中插入一个元素

void Insert(LNode* HL,const ElemType& item)

{

LNode* newptr;

newptr=new LNode;

newptr->data=item;

LNode *ap,*cp;

ap=HL;cp=HL->next;

while(cp!=HL)

if(item<cp->data)break;

else{ap=cp;cp=cp->next;}

newptr->next=cp;

ap->next=newptr;

}

(12)从单链表中删除表头元素

ElemType DeleteFront(LNode* HL)

{

if(HL->next==HL){

cerr<<"Deleteing from an empty list!"<<end1;

exit(1);

}

LNode* p=HL->next;

HL->next=p->next;

ElemType temp=p->data;

delete p;

return temp;

}

(13)从单链表中删除等于给定值的第一个元素

int Delete(LNode* HL,const ElemType& item)

{

LNode*ap=HL,*cp=HL->next;

while(cp!=HL)

if(cp->data==item)break;

else{ap=cp;cp=cp->next;}

if(cp==HL){

cerr<<"Deleted element is not exitst!"<<end1;

return 0;

}

else{

ap->next=cp->next;

delete cp;

return 1;

}

}

(14)利用单链表进行数据排序

void LinkSort(ElemType a[],int n)

{

LNode* head=new LNode;

InitList(head);

int i;

for(i=0;i<n;i++)

Insert(head.a[i]);

LNode* p=head->next;

i=0;

while(p!=head){

a[i++]=p->data;

p=p->next;

}

ClearList(head);

delete head;

}

*8.对于结点类型为DNode的双向链表,编写出下列每一个算法。

⑴向双向链表的未尾插入一个值为x的结点。

解:void InsertRear(DNode*&DL,ElemType x)

{

//建立值为x的结点

DNode* newptr=new DNode;

newptr->data=x;

newptr->left=newptr->right=newptr;

//当链表为空时完成插入

if(DL==NULL){DL=newptr;return;}

//当链表不为空时完成插入

DNode*p=DL->left;

newptr->right=p->right;

DL->left=newptr;

newptr->left=p;

p->right=newptr;

}

⑵向双向循环表的第i个结点位置插入一个值为x的结点。

解:void Insert(DNode*&DL,int i, ElemType x)

{

//i值越界,退出执行

if(i<=0){

cerr<<"i is out range!"<<end1;

exit(1);

}

//建立值为x的新结点

DNode*newptr=new DNode;

newptr->data=x;

newptr->left=newptr->right=newptr;

//当链表为空同时i等于1时进行插入,i不为1则退出

if(DL==NULL)if(i==1){DL=newptr;return;}

else{out<<"i is range!"<<end1;

exit(1);

}

//实现i等于1时的插入

if(i==1){newptr->right=DL;

newptr->left=DL->left;

DL->left->right=newptr;

DL->left=newptr;

DL=newptr;

return;

}

//查找第i个结点

int k=1;

DNode*p=DL->right;

while(p!=DL){

k++;

if(k==i)break;

p=p->right;

}

//i值越界,退出执行

if(i>k+1){

cerr<<"i is out range!"<<end1;

exit(1);

}

//把newptr结点插入到p结点之前

newptr->right=p;

newptr->left=p->left;

p->left->right=newptr;

p->left=newptr;

return;

}

⑶从双向循环链表中删除值为x的结点。

解:bool Delete(DNode*&DL,ElemType x)

{

if(DL==NULL)return 0;

//当表头结点为x时则删除之

DNode*p=DL;

if(DL->data==x){

DL=DL->right;

p->left->right=DL;

DL->left=p->left;

delete p;

return 1;

}

//查找值为x的结点

p=p->right;

while(p!=DL){

if(p->data==x)break;

else p=p->right;

}

//不存在值为x的结点则返回0

if(p==DL)return 0;

//删除值为x的结点

p->left->right=p->right;

p->right->left=p->left;

delete p;

return 1;

}

9.假定有一种带头附加结点的链表,每个结点含三个域:data、next和range,其中data

为整型值域,next和range均为指针域,现在所有结点已经由next域链接起来,试编一算法

,利用range域把所有结点按照其值从小到大的顺序链接起来,当然由此域链接得到的单链

表的表头指针保存在表头附加结点的range域中。

解:void OrderList(SLNode* SL)

//假定SLNode类型为按题目要求所定义的结点类型,SL为指向表头附加结点的指针

{

SL->range=NULL;

for(SLNode*p=SL->next;p!=NULL;p=p->next)

{ //每循环一次把p所指向的结点按序插入到以range域链接的有序表中

SLNode*ap,*cp;

//为p结点寻找合适的插入位置

ap=SL;cp=ap->range;

while(cp!=NULL)

if(p->data<cp->data)

break;

else{

ap=cp;

cp=cp->range;

}

//插入位置在ap和cp之间,把结点插入其中

p->range=cp;

ap->range=p;

}

}

10.编一程序,实现下列功能:

⒈按照9题对结点的要求生成一个具有10个整数元素结点的带表头附加结点的根据next域

链接的链表,元素值由随机函数产生;

⒉按照next域链接的次序输出链表中每个结点的值;

⒊调用按第9题要求编写的操作算法;

⒋按照range域链接的次序输出链表中每个结点的值。

解:

//lx2-7.cpp

#include<isotream.h>

#include<stdlib.h>

typedef int ElemType;//规定元素类型为整型

struct SLNode//定义单链表结点

{

ElemType data;

SLNode*next;

SLNode*range;

};

void OrderList(SLNode* SL)

{

SL->range=NULL;

for(SLNode*p=SL->next;p!=NULL;p=p->next)

{

SLNode *ap,*cp;

//为p结点寻找合适的插入位置

ap=SL;cp=ap->range;

while(cp!=NULL)

if(p->data<cp->data)

break;

else{

ap=cp;

cp=cp->range;

}

//插入位置在ap和cp之间,把p结点插入其中

p->range=cp;

ap->range=p;

}

}

void main()

{

//按next域链接生成具有10个整数元素结点的链表

SLNode*a=new SLNode;

a->next=NULL;

int i;

SLNode* p;

for(i=0;i<10;i++){

p=new SLNode;

p->data=range()%30; //假定产生30以内的随机整数

p->next=a->next;

a->next=p;

}

//按next域链接的次序输出单链表

for(p=a->next;p!=NULL;p=p->next)

cout<<p->data<<"";

cout<<end1;

//调用按第9题要求编写的操作算法

orderList(a);

//按range域链接的次序输出单链表

for(p=a->range;p!=NULL;p=p->range)

cout<<p->data<<"";

cout<<end1;

}


查看更多