链表相关知识点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在各种信息管理系统中,需要用到大量的数据记录表格,如果采用数组记录,会出现两个问题,其一是数组必须定义确定的数目,所以要按照最大数目来定义数组的长度,会造成内存浪费,第二是在数组中插入或删除一个元素,需要移动大量数据,时间消耗大。解决以上问题,可以采用动态存储分配的数据 结构–链表。

一、存储空间的分配和释放

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)
函数原型:void
calloc(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)
函数原型:void
realloc(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;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值