提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
在各种信息管理系统中,需要用到大量的数据记录表格,如果采用数组记录,会出现两个问题,其一是数组必须定义确定的数目,所以要按照最大数目来定义数组的长度,会造成内存浪费,第二是在数组中插入或删除一个元素,需要移动大量数据,时间消耗大。解决以上问题,可以采用动态存储分配的数据 结构–链表。
一、存储空间的分配和释放
1.malloc(memory allocation)
函数原型:void *malloc(unsigned int size);由于基类型为void,需要进行强制类型转化
举例:int *p=(int *)malloc(sizeof(int));
stuct stud *p=(struct stud )malloc(sizeof(struct stud));当结构体类型改变时,申请空间会随之改变。
2.calloc(clear allocation)
函数原型:voidcalloc(unsigned int n,unsigned int size)
举例:int *p=(int *)calloc(10,sizeof(int));等价于int *p=(int *)malloc(sizeof(int)10);
相当于定义了10个整形元素的数组,p为数组名,可通过p[i++]遍历数组。
3.realloc(reset allocation)
函数原型:voidrealloc(void *p, size);其功能是使指针p重新指向大小为size的空间,起始地址不变
举例:double *p=(double *)malloc(sizeof(double));
int *q=realloc(p,sizeof(int));
4.free
int *p.*q=(int *)malloc(sizeof(int));
p=q;
q++;
free§;
说明:p只能是最后一次调用malloc或calloc返回的地址,如果free(q)则会发生错误,因为q++后,q已经改变。相当于借了100块钱,只还了99。
ps:使用上述函数需包括stdlib.h或alloc.h
二、链表
头指针指向没有数据元素的头结点,头结点指向首元结点。
1.单链表的创建
代码如下(示例):
typedef struct node
{ char name[20];
int number;
struct node *next;
}Node,*linklist;//定义每个结点
linklist initlist()//单链表初始化函数,定义头结点
{ linklist head;
head=(Node *)malloc(sizeof(int));//分配头结点的内存空间
head->next=NULL;
return head;//返回头指针
}
void creatbyrear(linklist head)//将头指针传入,尾插法创建单链表
{ Node *r,*s;
char name[20];
int number;
r=head;//r指向头结点
printf("请输入学生姓名和学号");
while(1)
{ scanf("%s",name);
scanf("%d",number);
if(number==0) break;
s=(Node *)malloc(sizeof(Node));
strcpy(s->name,name);
s->number=number;
r->next=s;//地址域指向新结点
r=s;//指针右移
}
r->next=NULL;
}
void creatbyhead(linklist head)//头插法创建链表
{ Node *r,*s;
char name[20];
int number;
r=head;//r指向头结点
printf("请输入学生姓名和学号");
while(1)
{ scanf("%s",name);
scanf("%d",number);
if(number==0) break;
s=(Node *)malloc(sizeof(Node));
strcpy(s->name,name);
s->number=number;
s->next=head->next;//新节点指向原来的首元结点
head->next=s;//头结点指向新节点
}
}
void output(linklist head)//输出单链表
{ Node *p;
p=head->next;
while(p)
{ printf("%s",p->name);
printf("%d",p->number);
p=p->next;
}
}
void main()
{ linklist ha,hb;
ha=initlist();
creatbyrear(ha);
output(ha);//头插法
hb=initlist();
creatbyrear(hb);
output(hb);//尾插法
2.单链表的插入,删除,查询
插入代码如下:
//链表的插入
void insert_in(struct Student *head,int i)//在第i个位置插入
{
struct Student *p,*s;
p=head;
int j=0;
while(p->next!=NULL && j<i)
{
p= p->next;
j++;
}//寻找i前一个元素的地址
if(p!=NULL)
{
printf("请你输入要插入的元素\n");
s=(struct Student *)malloc(sizeof(struct Student));
scanf("%d,%f",&s->num,&s->score);
s->next=p->next;
p->next=s;
}
}
//在表首位置添加新的结点
void inserthead(linklist head)
{......
s->next=head->next;
head->next=s;
}
//在最后添加新的结点
void insertrear(linklist head)
{ Node *p=head,*s;
while(p&&p->next)
p=p->next;
if(p)
{.....
p->next=s;
s->next=NULL;
}
}
删除代码如下:
void delete(linklist head,int pos)
{
Node *p=head,*q;
int j=0;
while(j<pos-1&&p)
{ p=p->next;
j++;}
if(p==NULL||p->next==NULL)
printf("the position is error");
else//关键部分
{ q=p->next;
p->next=q->next;
free(q);}
}
单链表的查询
Node *search(linklist head,char name[])
{
Node *p=head->next;
while(p0
{ if(strcpy(p->name,name)!=0)
p=p->next;
else
break;//查找成功
}
if(p==NULL)
printf("error");
return p;//返回该点的地址
}
单链表的长度
int listlength(linklist head)
{
int count=0;
Node *p=head->next;
while(p)
{ count++;
p=p->next;}
return count;
}
3.不带头结点的链表
1.插入操作
在首位置:s->next=head;head=s;头指针发生了变化,需要返回新的头指针;不在首位置与带头结点的操作一致。
2.删除操作
在首位置:q=head;head=head->next;free(q);需返回新的头指针
//尾插法
linklist head=NULL;
if(head==NULL)
{ head=s;
r=head;}
else
{ r->next=s;
r=s;}
//插入操作,i为插入位置
if(i==1)
{ s->next=head;//新节点指向第一个结点
head=s;//头指针变为新结点
}
else
{
p=head;
int j=1;
while(j<i-1&&p)
{
p=p->next;
j++;
}
if(p)
{
s->next=p->next;
p->next=s;
}
return head;
}
//删除操作
if(i==1)
{ q=head;
head=head->next;
free(q);
}
else
{
int j=1;
while(j<i-1&&p)
{
p=p->next;
j++;
}
if(p&&p->next)
{
q=p->next;
p->next=q->next;
free(q);
}
return head;
}
4.单链表的合并和逆转
//合并
SLNode* merge(SLNode *head1,SLNode *head2,SLNode *head3)
{
SLNode *p1,*p2,*p3;
p1=head1->next,p2=head2->next;p3=head3;//从第一个有数值的结点开始比较
while(p1!=NULL&&p2!=NULL)//当两表都没便利完
{
if(p1->data<=p2->data)
{
p3->next=p1;
p3=p3->next;
p1=p1->next;
}
if(p1->data > p2->data)
{
p3->next=p2;
p3=p3->next;
p2=p2->next;
}
if(p1!=NULL) p3->next=p1;//表二空了,直接接上表一
if(p2!=NULL) p3->next=p2;//表一空了,接上表二
}
}
//逆转:依次取出每个节点,作为第一个结点新插到链表中
void reverse(linklist head)
{
Node *p;
p=head->next;
head->next=NULL;
while(p)
{
p->next=head->next;
p=q;
p=p->next;
}
}