随着学期的结束,数据结构的课内学习也快要结束了,期末考试也快要来了。
由于实验的考试可以开卷考,但是书上的伪代码有些过于难懂了,所以我打算借着整理复习资料的机会,把数据结构常考的代码用程序语言实现,作为一个模板,方便大家参考,当然,由于每道题之间有些差别,即使本系列文章是用程序语言实现,也不可能符合每道题的需求,只是为了便于大家理解。另外,本系列文章是根据我手上的教材:《数据结构–用C语言描述》(耿国华主编),为了便于大家查找,我尽可能的多写一些注释,并且把此代码在书上的位置标出来。
创作声明:
1.我写这篇文章的目的不是因为觉得这本教材不好,而是为了大家更好的理解,也是我复习的过程,如果我有哪里写的不对或不好欢迎大家评论区批评指正。不要喷我,感谢~
2.既然是程序语言实现,那么编码过程中风格必然是依照我的代码习惯来写,比如我非常不喜欢宏定义,大家根据自己的情况适当修改。
3.由于一些算法比较难,考试不考,所以那些算法不会在本系列文章出现。
4.为了简化算法,一些必要的判断我就不写了,因为考试所考的操作大概率是符合条件的,比如本文章线性表插入操作,考试肯定是插在了允许插入的位置,那么判断插入位置的语句我就不写了,实际生产中请自行加入,以提高程序的鲁棒性。
5.为了减少宏定义,本系列文章的大部分操作均以整型(int)实现,请根据需要替换所需的数据类型。
那么本文先从最简单也是最基础的线性表开始
一、顺序表
1.按内容查找
此算法比较简单,略过不写,详情参考教材41页算法2.1,算法时间复杂度o(n)
2.插入操作,教材42页算法2.2,平均移动元素次数:n/2
typedef struct
{
int elem[100];
int last;
}seqlist;
void insert(seqlist *l,int i,int e)
{
int j;
for(j=l->last;j>=i-1;j--)
{
l->elem[j+1]=l->elem[j];//从后往前移
}
l->elem[i-1]=e;//插入新元素
l->last++;//表长加1
}
3.删除操作,43页2.3,平均移动元素次数:(n-1)/2
int Delete(seqlist *l,int i)
{
int j;
int temp=l->elem[i-1];
for(j=i;j<=l->last;j++)
{
l->elem[j-1]=l->elem[j];//从前往后移
}
l->last--;//表长减1
return temp;//课本使用指针返回,我个人更喜欢值返回
}
4.合并运算,45页2.4,书上写的挺清晰的,不再额外写一遍了,时间复杂度:o(LA->last+LB->last)
二、单链表
1.节点定义:
typedef struct node
{
int data;
struct node *next;
}node,*linklist;
2.初始化,见课本48页2.5,注意传参传指针的指针
3.头插法建立单链表,48页2.6,注意其输入顺序与逻辑顺序是相反的
void createfromhead(linklist l)
{
node *s;
int num;
while(1)
{
scanf("%d",&num);
if(!num)//输入0结尾
break;
s=(node*)malloc(sizeof(node);
s->data=num;
s->next=l->next;
l->next=s;
}
}
4.尾插法建立单链表,49页2.7
void createfromtail(linklist a)
{
node *r,*s;
r=a;
int n;
while(1)
{
scanf("%d",&n);
if(!n)//输入0结尾
break;
s=(node*)malloc(sizeof(node));
s->data=n;
r->next=s;
r=s;
}
r->next=NULL;
}
5.查找,50页2.8,2.9,两个算法放在一起写,时间复杂度,o(n)
void search(linklist a,int pos,int key)//pos是按位置查找的位置,key是按之查找的值,请根据所需操作修改本函数,并且自行添加返回操作
{
node *p=a->next;
int i=1,flag=1;
do
{
if(i==pos)//按位置查找的结束条件
{
flag=0;
break;
}
if(p->data==key)//按值查找的结束条件
{
flag=0;
break;
}
p=p->next;
}while(p!=a);
if(flag)
printf("没找到,略略略")
}
6.求长度,52页2.10,此算法比较简单,本文不再赘述
7.单链表插入,53页2.11,此算法比较简单,只是新增节点+修改指针,注意指针的方向,本文不再赘述
8.删除元素,54页2.12,此算法比较简单,只是修改指针+释放节点,注意指针的方向,本文不再赘述
9.合并55页2.13
linklist merge(linklist a,linklist b)
{
node *p,*q,*r;
linklist c;
c->next=NULL;
p=a->next;
q=b->next;
r=c;
while(p!=NULL && q!=NULL)
{
if(p->data <= q->data)//按顺序合并
{
r->next=p;
r=r->next;
p=p->next;
}
else
{
r->next=q;
r=r->next;
q=q->next;
}
if(p)
r->next=p;
else
r->next=q;
}
三、循环链表
1.建立链表,课本57页
基本算法同建立单链表,只不过最后一步让指针指向头结点,而不再是null了
2.合并算法,58页2.14,此算法比较简单,找到表位指针,修改指针指向即可
四、双向链表
1.节点定义
typedef struct dnode
{
int data;
node *prior;
node *next;
}dnode,*LinkList;
2.插入宇删除操作,60页2.16,2.17,注意指针修改的顺序
五.本章经典例题的实现
一元多项式相加
书上的代码还是挺清楚的,在此我仅仅介绍一下相加函数思路,首先他用两个指针指向第一个节点,把两者相加的结果存储在第一个链表,所以尾指针tail指向了polya,然后开始扫描两个多项式,如果第一个指数小,则tail指针后移(p所指的元素进入和多项式,也就是polya),如果二者相等,则系数相加,如果相加等于0了,那么这个节点就可以删掉了,系数和不等于0,则把和多项式对应的系数改为二者之和,继续扫描下一个,如果第一个指数大,则把第二个加到和多项式中,反复执行,只到有一个多项式扫描结束。后续只需把未扫描的多项式剩余部分加入即可。
不得不说作者的想法确实比我高明,我当时做这道题的思路非常繁琐,下面是我的思路,明显比作者的繁琐多了。
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
float xishu;
int zhishu;
struct node *next;
}node,*linklist;
void initlist(linklist *a)
{
*a=(node*)malloc(sizeof(node));
(*a)->next=NULL;
}
void createfromtail(linklist a,int count)
{
node *r,*s;
r=a;
while(count)
{
s=(node *)malloc(sizeof(node));
scanf("%f %d",&s->xishu,&s->zhishu);
r->next=s;
r=s;
count--;
}
r->next=NULL;
}
int length(linklist *a)
{
int i=1;
node *p=(*a)->next;
while(p->next!=NULL)
{
i++;
p=p->next;
}
return i;
}
void sort(linklist *l)
{
int tempz,i;
float tempx;
node *current=(*l)->next,*nextnode;
for(i=0;i<length(&(*l))-1;i++)
{
nextnode=current;
do
{
nextnode=nextnode->next;
if(nextnode->zhishu>current->zhishu)
{
tempz=current->zhishu;
current->zhishu=nextnode->zhishu;
nextnode->zhishu=tempz;
tempx=current->xishu;
current->xishu=nextnode->xishu;
nextnode->xishu=tempx;
}
}while(nextnode->next!=NULL);
current=current->next;
}
}
void add(linklist a,linklist b)
{
node *pa=a,*pb=b->next,*temp;
int flag=1;
do
{
pa=pa->next;
pb=b->next;
while(1)
{
if(pb->zhishu==pa->zhishu)
{
pa->xishu+=pb->xishu;
}
if(pb->next==NULL)break;
pb=pb->next;
}
}while(pa->next!=NULL);
pb=b->next;
do
{
flag=1;
pa=a;
do
{
pa=pa->next;
if(pa->zhishu==pb->zhishu)
{
flag=0;
break;
}
}while(pa->next!=NULL);
if(flag)
{
temp=(node*)malloc(sizeof(node));
pa->next=temp;
temp->xishu=pb->xishu;
temp->zhishu=pb->zhishu;
temp->next=NULL;
}
pb=pb->next;
}while(pb!=NULL);
}
void del(linklist *l)
{
node *p=*l;
do
{
if(p->next->xishu==0)
{
p->next=p->next->next;
}
else
{
p=p->next;
}
}while((p->next!=NULL)&&(p!=NULL));
}
int main()
{
int n1,n2,n3;
linklist A,B;
scanf("%d",&n1);
initlist(&A);
initlist(&B);
createfromtail(A,n1);
scanf("%d",&n2);
createfromtail(B,n2);
add(A,B);
sort(&A);
del(&A);
//showlist(A);
scanf("%d",&n3);
node *p=A;
while(n3&&(p->next)!=NULL)
{
p=p->next;
n3--;
}
printf("%.1f %d",p->xishu,p->zhishu);
return 0;
}
这道题和书上略微不同,这道题的多项式是降序排列的,书上是升序排列的,书上相互比较的方法保证了插入的大小顺序,而我没有保证插入顺序,还需要调用一下链表上的冒泡排序,链表上的冒泡排序就是sort函数,大家可以参考一下
这本书前面的代码可读性还是非常高的,所以前面的许多算法我就略过了,但是后面图的算法较为难懂,后面我尽量详细的为大家写一写
本文到此结束,欢迎大家评论区探讨交流。