链表

C语言数组中,不允许使用动态数组类型,为此,在C语言中推出了链表这个概念。

一、动态内存分配与静态内存分配。

所谓动态内存分配就是指在程序执行过程中动态地分配或者回收存储空间的分配内存的方法。与之相对,静态分配内存,预先分配存储空间,像数组。

动态内存的分配方法相对于静态内存的分配方法有如下两个特点:

1、不需预先分配存储空间。

2、分配的空间可以根据程序的需要扩大和缩小。

二、实现动态分配内存的函数。

1、malloc函数 void *malloc(unsigned int size)

函数malloc的作用是在内存的动态存储区中分配一个长度为size的连续空间。

值得注意的是:当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针,所以在调用函数时应该检测返回值是否是NULL,并添加相应的处理语句。

下面是一个malloc的例子:

#include <stdio.h>

#include <stdlib.h>

void main()

{

int count ,*array;

if((array=(int*)malloc(10*sizeof(int)))==NULL)

{

printf("Assgin failed");

exit(1);

}

for(count=0;count<10;count++)

 array[count]=count;

for(count=0;count<10;count++)

printf("%2d",array[count]);


}

2.calloc函数

(类型说明符*)calloc(n,size)

函数功能为:在内存动态存储区中分配n块长度为“size“字节的连续区域,函数的返回值为该区域的首地址,其中 (类型说明符*)用于强制类型转换。

calloc与malloc的区别仅在于前者一次可以分配n块区域,例如

p=(struct stu*)calloc(2,sizeof(struct stu));

其中:按stu的长度分配两个连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。

3、释放函数free

void free(void *p)

其功能是释放指针p所指向的内存区。其中”p"必须是先前调用malloc函数或calloc函数时返回的指针。

在此重要的是指针的值,而不是用来申请动态内存的指针本身。例如:

int *p1,*p2;

p1=malloc(10*sizeo(int));

p2=p1;

....

free(p2);//或者free(p1),此时p1、p2都可作为free函数的参数。

4、realloc函数

void *realloc(void *mem_address, unsigned int newsize);

指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。//新的大小一定要大于原来的大小不然的话会导致数据丢失!

功能:先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域,同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

三、链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接秩序实现的。链表由一系列的结点组成,结点可以再运行时动态生成,每个结点包括两部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

如果在矩阵中,多数的元素为0,称此矩阵为稀疏矩阵(sparse matrix)。

1、简单线性链表的模型 老鹰捉小鸡

#include <stdio.h>

struct Chicken

{

char Name [20];

struct Chicken *next;

};

void main()

{

struct Chicken No4={"Chicken No4",NULL};

struct Chicken No3={"Chicken No3",NULL};

struct Chicken No2={"Chicken No2",NULL};

struct Chicken No1={"Chicken No1",NULL};

struct Chicken Hen={"Hen",NULL};

struct Chicken *pChicken=NULL;

/*建立链表*/

Hen.next=&No1;

No1.next=&No2;

No2.next=&No3;

No3.next=&No4;

/*遍历链表*/

pChicken=&Hen;

while(pChicken!=NULL)

{

printf("%s \n",pChicken->Name);

pChicken=pChicken->next;

}

}

问卷调查问题:
#include <stdio.h>
#include <stdlib.h>
struct mm
{
char mingzi[20];
char xingbie;
char daan;
struct mm *next;
};
void main()
{
struct mm *pHead=NULL;
struct mm *pOne=NULL;
struct mm *pPrevOne=NULL;
/*在内存中动态创建一个struct mm 对象*/


pOne=malloc(sizeof(struct mm));
pPrevOne=pHead=pOne;
/*strcpy(pOne->mingzi,"mingzi");*/
/*打印提示信息*/
printf("\nmingzi\txingbie(M/F)\tdaan(Y/N)");
printf("\n-------------------\n");
pHead->next=NULL;


while(1)
{
/*读入当前的调查结果*/
scanf("%s %c %c",pOne->mingzi,&(pOne->xingbie),&(pOne->daan));
if(strcmp(pOne->mingzi,"Q")==0)
{
/*结束输入,对最后读入的对象进行处理*/
strcmp(pOne->mingzi," ");
pOne->xingbie=' ';
pOne->daan=' ';
pOne->next=NULL;
        break;
}
pPrevOne=pOne;/*保存当前对象的地址*/
pOne=(struct mm*)malloc(sizeof(struct mm));
/*新对象的地址存储到当前对象的next成员变量*/
pPrevOne->next=pOne;


}
      printf("\n mingzi\txingbie(M\F)\tdaan(Y\N)\t\n");
 printf("\n----------\n");
 pOne=pHead;
 while(pOne->next!=NULL)
 {
 /*打印当前对象的信息*/
 
printf("\n%s\t%c\t%c \n",pOne->mingzi,pOne->xingbie,pOne->daan);
pOne=pOne->next;/*指向链表的下一个对象*/


 }
 /*删除链表*/
 pOne=pHead;
 while(pOne->next!=NULL)
 {
 pPrevOne=pOne;
 pOne=pOne->next;
 free(pPrevOne);
 }

}

2、单向链表

链表结构中包含指针类型的结构成员,其类型为指向相同结构类型的指针。根据C语言的语法要求,结构成员不能是结构自身类型,即结构不能自己定义自己,因为这样将导致一个无穷的递归定义,但结构的成员可以是结构自身的指针类型,通过指针引用自身这种类型的结构。

例:

include <stdio.h>
 
typedef struct node
{
	int info;
	struct node *next;
}LINKLIST;
 
void main()
{
LINKLIST *head,*p,x,y,z;
x.info=10;
y.info=20;
z.info=30;
head=&x;
x.next=&y;
y.next=&z;
z.next=NULL;
 
p=head;
while(p!=NULL)
{
	printf("%d \n",p->info);
	p=p->next;
}
 
}
3、对链表的各种操作

/*在结点P后插入一结点*/
void insert(LINKLIST *p,DATATYPE x)
{
   LINKLIST *newp=new(LINKLIST);
   newp->info=x;
   newp->next=p->next;
   p->next=newp;
}
/*删除结点p后面的结点*/
void delete(LINKLIST *p)
{
LINKLIST *temp;
temp=p->next;
p->next=p->next->next;
delete(temp);
}
/*遍历链表*/
void outputlist(LINKLIST *head)
{
  LINKLIST *current=head->next;
  while(current!=NULL)
  {
 printf("%d \n",current->info);
       current=current->next;
  }
  return ;
}
/*创建链表*/
struct node *create(unsigned int size)
{
struct node *phead=NULL;
struct node *pone=NULL;
struct node *pprevone=NULL;
int i;
pone=(struct node *)malloc(sizeof(struct node));
pone->next=NULL;
pprevone=phead=pone;
/*构建循环*/
for(i<0;i<size;i++)
{
pprevone=pone;
pone=(struct node *)malloc(sizeof(struct node));
pprevone->next=pone;


}
return phead;
}
/*删除整个链表*/
void removeall(struct node *list)
{
     struct node *phead=NULL;
struct node *pone=NULL;
pone=list;
while(pone->next!=NULL)
{
pprevone=pone;
pone=pone->next;
free(pprevone);
}
 
}
/*在链表中插入结点*/
int insert(struct node *list,int i,struct node *node)/*list为链表的第一个结点地址,I为第n个元素,如果存在,返回i,否则返回0*/
{
struct node *pone=NULL;
struct node pnewone=NULL;
int j=0;
pone=list
/*顺序查找,直到到达链表的尾部或j=i*/
while((pone!=NULL)&&(j<i-1))
{
pone=pone->next;
j++;
}
if((pone->next==NULL)||(j>i-1))/*第i个元素不存在*/
return 0;
pnewone=(struct node *)malloc(sizeof(struct node));
/*复制参数node信息到新增加的结点pnewone*/
pnewone->next=node->next;


pnewone->next=pone->next;/*将下一结点的地址复制到插入结点的成员变量中*/
pone->next=pnewone;/*将插入结点的地址复制到当前结点的成员变量中*/
return j;
}


 /*在链表中删除结点*/
int removeElment(struct node *list,int i)
{
   /*list为链表第一个结点地址,i为第n个元素,如果存在返回i,否则返回0*/
struct node *pone=NULL;
struct node *pdeleteone=NULL;
int j=0;
pone=list;
while((pone!=NULL)&&(j<i-1))
{
       pone=pone->next;
  j++;
}
if((pone->next==NULL)||(j>i-1))
{
return 0;
}
    pdeleteone=pone->next;
pone->next=pdeleteone->next;
free(pdeleteone);
return j;
}

4、双链表

#include <stdio.h>
#define N 3;
typedef struct node
{
char name[20];
struct node *llink,*rlink;
}stud;
stud *creat(int n)
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("Assign memory failed!\n");
exit(1);
}
h->name[0]='\0';
h->llink=NULL;
h->rlink=NULL;
p=h;
for(i=0;i<n;i++)
{
        if((s=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配内存空间!\n");
exit(1);
}
p->rlink=s;
printf("Please input the %d th's name \n",i+1);
scanf("%s",s->name);
s->llink=p;
s->rlink=NULL;
p=s;
}
   h->llink=s;
   p->rlink=h;
   return(h);
}
stud *search(stud *h,char *x)
{
stud *p;
char *y;
p=h->rlink;
while(p!=h)
{
y=p->name;
if(strcmp(y,x)==0)
      return (p);
         else
p=p->rlink;



}
printf("NO DATA \n");


}
void print(stud *h)
{
int n;
stud *p;
p=h->rlink;
printf("The result is: \n");
while(p!=h)
{
      printf("%s \n",&*(p->name));
 p=p->rlink;
}
printf("\n");
}
void main()
{
int number;
char studname[20];
stud *head,*searchpoint;
number=N;
//clrscr();/*清除文本模式窗口 清屏的意思*/
head=creat(number);
print(head);
printf("Please input name \n");
scanf("%s",studname);
searchpoint=search(head,studname);
printf("The result is :%s \n",*&searchpoint->name);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值