这样一种存储方式,其存储元素的个数是不受限定的,当进行添加元素时,存储的个数就会随之改变,这种存储方式就是链表。
链表中有一个头指针变量,head就是头指针,在这个指针变量中保存一个地址。这个地址为一个变量的地址。这个变量称为元素。
一个元素包裹两部分:数据部分和指针部分
1.单链表的建立
动态创建一个节点时,要为其分配内存。
malloc()函数:void *malloc(unsighned int size);
该函数的作用就是在内存中动态的分配一块size大小的内存空间。malloc函数返回一个指针,该指针指向分配的内存空间,若出现错误,则返回NULL
calloc()函数:void *calloc(unsighned int n,unsighned int size);
该函数就是n个长度为size的连续内存空间数组。calloc会返回这样一个指针,该指针指向动态分配的内存空间的地址。
free()函数:void free(void *ptr);
free函数无返回值
该函数的功能是使由指针ptr指向的内存区,使部分内存区能被其他变量使用。
2.单链表表的插入、删除
以下为完整的链表操作实例
//完整的链表操作代码
#include<stdio.h>
#include<stdlib.h>
struct Student
{
char cName[20];//姓名
int iNumber; //学号
struct Student* pNext;
};
int iCount;//全局变量表示链表长度
struct Student* Create()
{
struct Student* pHead=NULL;//初始化链表头指针为空
struct Student* pEnd,*pNew;
iCount=0; //初始化链表长度
pEnd=pNew=(struct Student*)malloc(sizeof(struct Student));
printf("首先输入姓名,然后输入学号\n");
scanf("%s",&pNew->cName);
scanf("%d",&pNew->iNumber);
while(pNew->iNumber!=0)
{
iCount++;
if(iCount==1)
{
pNew->pNext=pHead;//使得指向为空
pEnd=pNew;//跟踪新加入的节点
pHead=pNew; //头指针指向首节点
}
else
{
pNew->pNext=NULL;
pEnd->pNext=pNew;
pEnd=pNew;
}
pNew=(struct Student*)malloc(sizeof(struct Student));//再次分配节点内存空间
scanf("%s",&pNew->cName);
scanf("%d",&pNew->iNumber);
}
free(pNew); //释放没有用dao的空间
return pHead;
}
void Print(struct Student* pHead)
{
struct Student *pTemp; //循环所用的临时指针
int ilndex=1; //表示链表中节点的序号
printf("---这个链表中有%d个成员:-----\n",iCount);//消息提示
printf("\n");
pTemp=pHead;
while(pTemp!=NULL)
{
printf("member %d is \n",ilndex);
printf("name %s is\n",pTemp->cName);
printf("number %d is\n",pTemp->iNumber);
printf("\n");
pTemp=pTemp->pNext;
ilndex++;
}
}
struct Student* Insert(struct Student* pHead)
{
struct Student* pNew;
printf("--首先插入一个成员--\n");
pNew=(struct Student*)malloc(sizeof(struct Student));
scanf("%s",&pNew->cName);
scanf("%d",&pNew->iNumber);
pNew->pNext=pHead;
pHead=pNew;
iCount++;
return pHead;
}
void Delete(struct Student* pHead,int ilndex)
{
int i;//控制循环变量
struct Student *pTemp; //临时指针 i
struct Student *pPre; //..删除节点钱的节点
pTemp=pHead;//得头节点
pPre=pTemp;
printf("删除地%d个成员\n",ilndex);
for(i=1;i<ilndex;i++)
{
pPre=pTemp;
pTemp=pTemp->pNext;
}
pPre->pNext=pTemp->pNext;
free(pTemp);
iCount--;
}
main()
{
struct Student *pHead;
pHead=Create();
pHead=Insert(pHead);
Delete(pHead,2);
Print(pHead);
return 0;
}
离散 298990
张思 898989
王五 334343
李六 334342
力气 232323
//合并两个链表操作实例
//合并两个链表
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
typedef struct student
{
int num;
struct student *next;
}LNode,*LinkList;
LinkList create()
{
LinkList head;
LNode *p1,*p2;
char a;
head=NULL;
a=getchar();
while(a!='\n')
{
p1=(LNode*)malloc(sizeof(LNode)); //分配空间
p1->num=a;
if(head==NULL)
{
head=p1;
}
else
{
p2->next=p1;
}
p2=p1;
a=getchar();
}
p2->next=NULL;
return head;
}
LinkList coalition(LinkList L1,LinkList L2)
{
LNode *temp;
if(L1==NULL)
{
return L2;
}
else
{
if(L2!=NULL)
{
for(temp=L1;temp->next!=NULL;temp=temp->next);//遍历L1知道尾节点
temp->next=L2;
}
}
return L1;
}
main()
{
LinkList L1,L2,L3;
printf("please input two chains:\n");
printf("The number one chain is :\n");
L1=create();
printf("The number two chain is:\n");
L2=create();
coalition(L1,L2);
printf("合并后的链表是:\n");
while(L1)
{
printf("%c ",L1->num);
L1=L1->next;
}
getch();
}
3.循环链表
链表中最后一个节点的指针域指向头节点,使链表形成一个环,从表中任意一个节点出发,均可以找到其他节点。与普通链表相比,只是在算法中循环遍历链表节点时,判断条件不是p->next==NULL,而是p->next==head
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
typedef struct student
{
int num;
struct student *next;
}LNode,*LinkList;
LinkList create()
{
LinkList head;
LNode *p1,*p2;
char a;
head=NULL;
a=getchar();
while(a!='\n')
{
p1=(LNode*)malloc(sizeof(LNode)); //分配空间
p1->num=a;
if(head==NULL)
{
head=p1;
}
else
{
p2->next=p1;
}
p2=p1;
a=getchar();
}
p2->next=head;
return head;
}
main()
{
LinkList L1,head;
puts("please create a chain\n");
L1=create();
head=L1;
printf("This chain is:\n");
printf("%c ",L1->num);
L1=L1->next;
while(L1!=head)
{
printf("%c ",L1->num);
L1=L1->next;
}
printf("\n");
}
4.chuang'jian's
创建双向链表
//创建双向链表,将链表中的数据输出到窗体上,然后输入要查找学生的姓名,将学生姓名熊表中删除,并显示删除后的链表
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node
{
char name[20];
struct node *prior,*next;
}stud;
stud *create(int n)
{
stud *p,*h,*s; //p时当前节点,h时头节点,s是临时节点
int i;
h=(stud*)malloc(sizeof(stud));
h->name[0]='\0';
h->prior=NULL;
h->next=NULL;
p=h;
for(i=0;i<n;i++)
{
s= (stud*)malloc(sizeof(stud));
p->next=s;
printf("输入第%d个学生的姓名:",i+1);
scanf("%s",&s->name);
s->prior=p;
s->next=NULL;
p=s;
}
p->next=NULL;
return (h);
}
stud *search(stud *h,char *c)
{
stud *p;
char *y;
p=h->next;
while(p)
{
y=p->name;
if(strcmp(y,c)==0)
{
return (p);
}
else
{
p=p->next;
}
}
puts("no this node\n");
}
void del(stud *p)
{
p->next->prior=p->prior;
p->prior->next=p->next;
free(p);
}
main()
{
int number;
char sname[20];
stud *head,*sp;
puts("please input the size of chain:\n");
scanf("%d",&number);
head=create(number);
sp=head->next;
printf("现在这个双链表是:\n");
while(sp)
{
printf("%s ",&*sp->name);
sp=sp->next;
}
printf("\n请输入你要查找的名字:\n");
scanf("%s",sname);
sp=search(head,sname);
printf("\n你想查找的姓名是%s:\n",*&(sp->name));
del(sp);
sp=head->next;
puts("现在的双链表是:\n");
while(sp)
{
printf("%s ",&*(sp->name));
sp=sp->next;
}
printf("\n");
puts("\nany key to exit...");
}
这里面还涉及到一个c的知识点,关于typedef
c语言不仅提供了丰富的数据类型,还允许用户自己定义 类型说明符。
即 允许由用户 为数据类型 取“别名”。类型定义符tyoedef就是这个功能
typedef 原类型名 新类型名
类似上面的例子中,结构的结构名为LNode和LinkList,
那么就可以直接用结构名 定义结构体变量
即typedef可以声明各种类型名,但是不可以定义变量。
eg:typedef int ARR[10];
ARR a,b,c; 代表定义的数组a,b,c,分别都含有十个元素。
typedef int INTEGER; INTEGER i;代表定义的i为int类型。