//带头结点的单链表的初始化,建立,插入,查找,删除
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;//定义数据域类型
typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。
在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。
结构体中的 typedef struct Node 的意思就是,为自定义的数据类型定义一个新名字 Node。
//定义结点类型(由数据域,指针域组成)和链表LinkList/
typedef struct Node
{
ElemType data; //单链表的数据域
struct Node *next; //单链表的指针域
}Node,*LinkedList;
关于结构体 struct Node *next; 这么一句代码,为什么要这么写?我写成 int *next 行不行?
不行的。next是指向下一个Node,所以其类型必须是Node。int *next 只能指向int,而不能指向Node。所以必须定义为 Node 类型,但是 Node 是结构体,所以前面还得加上个 struct。
//单链表的初始化/
LinkedList LinkedListInit()
{
Node *L;
L=(Node *)malloc(sizeof(Node)); //申请结点空间
if(L==NULL) //判断是否有足够的内存空间
printf("申请内存空间失败");
L->next=NULL; //将next设置为NULL,初始长度为0的单链表.com
}
//单链表的建立1,头插法建立单链表/
LinkedList LinkedListCreateH()
{
Node *L;
L=(Node *)malloc(sizeof(Node)); //申请头结点空间
L->next=NULL; //初始化一个空链表
ElemType x; //x为链表数据域中的数据
while(scanf("%d",&x)!=EOF)
{
Node *p;
p=(Node *)malloc(sizeof(Node)); //申请新的结点
p->data=x; //结点数据域赋值
p->next=L->next; //将结点插入到表头
L->next=p;
}
return L;
}
//单链表的建立2,尾插法建立单链表/
LinkedList LinkedListCreateT()
{
Node *L;
L=(Node *)malloc(sizeof(Node)); //申请头结点空间
L->next=NULL; //初始化一个空链表
Node *r;
r=L; //r始终指向终端结点,开始时候指向头结点
ElemType x; //x为链表数据域中的数据
while(scanf("%d",&x)!=EOF)
{
Node *p;
p=(Node *)malloc(sizeof(Node)); //申请新的结点
p->data=x;
r->next=p ;
r=p;
}
return L;
}
//单链表的插入,在链表的第i个位置插入x的元素
LinkedList LinkedListInsert(LinkedList L,int i,ElemType x)
{
Node *pre; //pre为前驱结点
pre=L;
int temi=0;
for(temi=1;temi<i;temi++)
pre=pre->next ; //查找第i个位置的前驱结点
Node *p;
p=(Node *)malloc(sizeof(Node));
p->data=x;
p->next=pre->next;
pre->next=p;
}
return L;
}
//单链表的删除,在链表中删除值为x的元素
LinkedList LinkedListDelete(LinkedList L,ElemType x)
{
Node *p ,*pre; //pre为前驱结点,p为查找的结点;
p=L->next;
whiel(p-<data!=NULL)
{
pre=p;
p=p->next;
}
pre->next=p->next; //删除操作,将其前驱的next指向其后继
free(p);
return L;
}
int main()
{
LinkedList list,start;
printf("请输入单链表的数据:");
list = LinkedListCreatT();
for(start = list->next; start != NULL; start = start->next)
printf("%d ",start->data);
printf("/n");
int i;
ElemType x;
printf("请输入插入数据的位置:");
scanf("%d",&i);
printf("请输入插入数据的值:");
scanf("%d",&x);
LinkedListInsert(list,i,x);
for(start = list->next; start != NULL; start = start->next)
printf("%d ",start->data);
printf("/n");
printf("请输入要删除的元素的值:");
scanf("%d",&x);
LinkedListDelete(list,x);
for(start = list->next; start != NULL; start = start->next)
printf("%d ",start->data);
printf("/n");
return 0;
}
//题外话:
//带头结点初始化
Node *head; //声明头结点
void InitList(Node **head)
{
*head=(Node *)malloc( sizeof(Node));
(*head)->next=NULL;
}
//不带头结点初始化
方式一:
void InitList(Node **head){
*head=NULL;
}
调用InitList(&head);
方式二:
void InitList(Node *head){
head=NULL;
}
//带头结点的单链表,初始时一定返回的是指向头结点的地址,所以一定要用二维指针,否则将导致内存访问失败或异常。
相关知识拓展:
malloc()到底从哪里得到了内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。就是这样!
什么是堆:堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。
堆一般由程序员分配释放,若不释放,程序结束时可能由OS回收。注意这里说是可能,并非一定。所以我想再强调一次,记得要释放。