一、单链表
链表:不像顺序表一样占据一段连续的内存空间,储存单元是分撒的任意的地址,每个数据都存放到链表的节点中,每个节点由指针连在一起。每个节点可以是结构体类型元素,每个节点包括指针域和数据域,其中表尾指针域置为空NULL
顺序表的优势:顺序表可以随机访问其中的元素,而链表不可以。就是因为顺序表的底层是数组,而数组是可以通过下标达到随机访问的目的。而链表只能通过指针去遍历访问。a[3] , a[8]数组可以随机访问,但是链表不可以,需要指针,索引,一个个遍历。顺序表也可以通过指针p,类似数组,p+4,p+9随机,访问数据,顺序表地址必须是挨着的。
#include<stdio.h>
#include<stdlib.h>
//定义任意数据
typedef struct data
{
char * num;
float score;
char name[10];
long index;
}DataType,*P_DataType;
typedef struct node
{
DataType data; // 结构体数据类型,可以是任何想要定义的类型
struct node *next;//指向本身,结构体数据类型的指针
}Linknode,*P_LinkList;
P_LinkList CreatInitLinkHead();
int NewLinkNode_InsertToListTail(P_LinkList Head,DataType *data,int size);
int ShowLinkList(P_LinkList Head);
int InsertToLinkList_anypos(P_LinkList Head,int index, DataType *data,int size);
int Delenode2(P_LinkList Head,int index);
//插入元素,并输出,然后,任意位置插入,输出
int main()
{
P_LinkList Head = NULL;
int rt = -1;
//1创建链表
if( (Head = CreatInitLinkHead()) == NULL ) {
printf("Creat Init LinkHead fainl \r\n");
return -1;
} else {
printf("Creat Init LinkHead success \r\n");
}
//2插入数据
DataType data1 = {
.num = "zhang san",
.index = 1,
};
DataType data2 = {
.num = "li si",
.index = 2,
};
DataType data3= {
.num = "da piao liang",
.index = 3,
};
DataType data4= {
.num = "xiao bie san",
.index = 4,
};
P_DataType a[4] = {&data1,&data2,&data3,&data4};
int size = sizeof(DataType);
int i = 0;
for(i=0; i <4; i++) {
rt = NewLinkNode_InsertToListTail(Head ,a[i],size);
if(rt < 0) {
printf("NewLinkNode_InsertToListTail fainl \r\n");
return -1;
}
else {
printf("NewLinkNode_InsertToListTail succcess \r\n");
}
}
//3 输出显示链表
rt = ShowLinkList(Head );
if(rt < 0) {
printf("ShowLinkList fainl \r\n");
return -1;
}
//4 随意位置插入数据
DataType data22 = {
.num = "li si 2 ",
.index = 2,
};
DataType data33= {
.num = "da piao liang 2",
.index = 33,
};
DataType data44= {
.num = "xiao bie san 2",
.index = 4,
};
P_DataType aa[3] = {&data22,&data33,&data44};
for(i=0; i <3; i++) {
rt = InsertToLinkList_anypos(Head ,aa[i]->index,aa[i],size);
if(rt < 0) {
printf("InsertToLinkList_anypos fainl \r\n");
return -1;
}
else {
printf("InsertToLinkList_anypos succcess \r\n");
}
}
//5,重新输出显示数据
rt = ShowLinkList(Head );
if(rt < 0) {
printf("ShowLinkList fainl \r\n");
return -1;
}
return 0;
}
//,创建链表,定义一个结构体类型指针函数,此函数返回一个指针
P_LinkList CreatInitLinkHead()
{
P_LinkList Head = NULL;
if( (Head =(P_LinkList)malloc(sizeof(Linknode))) == NULL ) {
return Head ;
}
//Head ->data =0;
Head ->next = NULL;
return Head ;
}
//新建节点插入头部
int NewLinkNode_InsertToListHead(P_LinkList Head,DataType *data,int size) {
if(Head ==NULL) {
printf("NewLinkNode_InsertToListHeadHead is null \r\n");
return -1;
}
P_LinkList Pnode= NULL;
if( (Pnode=(P_LinkList)malloc(sizeof(Linknode))) == NULL ) {
printf("NewLinkNode_InsertToListHeadmalloc fail\r\n");
return -1;
}
memcpy(&(Pnode->data),data,size);
Pnode->next = Head->next;
Head->next = Pnode;
return 0;
}
//新建节点插入尾部
int NewLinkNode_InsertToListTail(P_LinkList Head,DataType *data,int size) {
if(Head == NULL) {
printf("NewLinkNodeToListfail Head is null \r\n");
return -1;
}
P_LinkList Pnode = NULL;
Pnode = Head ;
while(Pnode->next != NULL) { //或//while(Pnode->next)
Pnode = Pnode->next;
}
P_LinkList Pnode2 = NULL;
if( (Pnode2=(P_LinkList)malloc(sizeof(Linknode))) == NULL ) {
printf("NewLinkNodeToListmalloc fail\r\n");
return -1;
}
memcpy(&(Pnode2->data),data,size);
Pnode->next = Pnode2;
Pnode2->next = NULL;
return 0;
}
//新建节点插入任意位置
int InsertToLinkList_anypos(P_LinkList Head,int index, DataType *data,int size) {
if(Head == NULL) {
printf("InsertToLinkList fail Head is null \r\n");
return -1;
}
P_LinkList Pnode= NULL;
Pnode = Head ;
while(Pnode->next != NULL) { //或//while(Pnode->next)
if(Pnode->data.index == index)
break;
Pnode = Pnode->next;
}
P_LinkList Pnode2= NULL;
if( (Pnode2 =(P_LinkList)malloc(sizeof(Linknode))) == NULL ) {
printf("InsertToLinkList malloc fail\r\n");
return -1;
}
memcpy(&(Pnode2->data),data,size);
Pnode2->next = Pnode->next;
Pnode->next = Pnode2;
return 0;
}
//输出链表所有元素
int ShowLinkList(P_LinkList Head)//定义一个输出链表函数
{
if(Head == NULL) {
printf("Head is null \r\n");
return -1;
} else {
P_LinkList Pnode= NULL;
Pnode = Head ;
do
{
printf("%d:%s ->\n",Pnode->data.index,Pnode->data.num);
Pnode = Pnode ->next;
}while(Pnode !=NULL);//直到表尾
}
return 0;
}
//删除节点函数1,知道节点的指针
void delenode(linklist *list, linklist q)
{
linklist ptr;
if(q == list)//如果删除的是第一个表头位置节点
{
*list = q->next//表头指针域赋给表头指针;
free(q);//释放指针
}
else
{
for(ptr = list; ptr->next!=q; ptr = ptr->next/*后驱的指针放在了前驱的指针域里*/);//遍历链表找到相应节点指针
if(ptr->next !=NULL)//没有出到表尾
{
ptr->next =q->next;//直接把要删除节点指针域赋给前驱节点指针域
free(q);//释放这个节点得指针
}
}
}
//删除节点函数2
int Delenode2(P_LinkList Head,int index)
{
if(Head == NULL) {
printf("Delenodefail Head is null \r\n");
return -1;
}
P_LinkList Pnode = NULL;
Pnode = Head ;
if(Head->data.index == index)//如果删除的是第一个表头位置节点
{
Pnode = Head->next;
free(Head);
Head = Pnode;
}
while(Pnode->next != NULL && (Pnode->next->data.index != index)) {
Pnode = Pnode->next;
}
if(Pnode->next->data.index == index)// 必须找到了,才能去删除
{
P_LinkList delPnode = Pnode->next;
Pnode->next = Pnode->next->next;
free(delPnode);
}
return 0;
}
//销毁链表函数
void Destory(P_LinkList Head )
{
if(Head ==NULL) {
printf("Head is null \r\n");
return -1;
}
P_LinkList Pnode = NULL;
Pnode = Head ;
while(Pnode->next != NULL) { //或//while(Pnode->next)
Head = Pnode->next;
free(Pnode );
Pnode = Head ;
}//直到最后一个指针
free(Pnode);
Head = NULL;
}
输出结果
本例子中index,作为索引,方便查找,插入位置,但是如果数据过于庞大,不能采用最好,修改后面所有的index,时间会很长,看用在什么场景。本文没有给出修改index的操作
删除链表节点后
Delenode2(Head,2);
Delenode2(Head,33);
Delenode2(Head,4);
2、第二种写法
#include<stdio.h>
typedef int elemtype;
typedef struct node{
elemtype date//数据域;
struct node *next;//指向结构体型指针域
}lnode,*linklist;//这里定义了两个变量,一个普通结构体类型数据变量,一个指向结构体的指针变量,后面定义的指针都为这类型
linknode Creatlink(int n)//定义一个返回指针的函数 与上个例子相似
{
linknode p1,p2,head = null;//定义指针变量
int i;
elemtype elem;
for(i = 1; i < n; i++)//建立n个节点的链表
{
scanf("%d",&elem);//输入数据域
p1 = (linklist)malloc(sizeof(lnode));
p1->date = elem;
p1->next = NULL;
if(!head)
head = p1;//如果为是第一个表则把第一个节点的指针赋给头指针
else
p2->next = p1;//后驱的指针赋给前驱指针域
p2 = p1;//前驱指针换为后驱指针
}
return (head);
}
void insertnode(linklist *list, linklist q, elemtype elem)//定义一个插入节点函数
{
linklist ptr;
ptr = (linklist)malloc(sizeof(elemtype));
ptr->date = elem;
if(!list)//如果只有一个节点空表
{
*list = ptr;//赋给头指针
ptr->next = NULL;
}
else
{
ptr->next = q->next;//只需把要插入的位置的指针域赋给新建的节点的指针域
q->next = ptr;//新建的指针赋给要插入得位置节点指针域
}
}
int head_insert() {
}
void delenode(linklist *list, linklist q)//定义一个删除节点函数
{
linklist ptr;
if(q == list)//如果删除的是第一个表头位置节点
{
*list = q->next//表头指针域赋给表头指针;
free(q);//释放指针
}
else//删除的是表头后节点
{
for(ptr = list; ptr->next!=q; ptr = ptr->next/*后驱的指针放在了前驱的指针域里*/);//遍历链表找到相应节点指针
if(ptr->next !=NULL)//没有出到表尾
{
ptr->next =q->next;//直接把要删除节点指针域赋给前驱节点指针域
free(q);//释放这个节点得指针
}
}
}
void Destory(linklist *list)//销毁链表函数
{
linklist p, q;
p = *list;//从表头开始
while(p)//直到表尾
{
q = p->next;//前驱的指针域赋给后节点得指针
free(p);
p = q;//重新指向这个节点
}
*list = NULL;//最后需制空。防止野指针
}
main()//主函数
{
int elem, i;
linklist L,q;//定义一张表
q = L = Creatlink(1);//调用建表函数并获得表头指针
scanf("%d",&elem);输入数据
while(elem)//用于判断结束循环。当输入位0时结束
{
insertnode(&L, q,elem);//调用插入函数
q = q->next;//不断或得前驱的指针域以逻辑上各节点连接起来
scanf("%d",&elem);//不断输入元素
}
q = L;//或得表头指针
printf("the content of the linklist\n");
while(q)//直到表尾空指针
{
printf("%d ",q->date);//输出数据
q = q->next;//循环获得后驱的指针
}
printf("\n");
q = L;//获得表头地址指针
printf("the content of the deleay linklist\n");
for(i = 0; i < 4; i++)//循环5次获得第5个节点的指针域
{
q = q->next;//获得要删除节点的指针域
}
delenode(&L, q);//调用删除节点函数
q = L;
while(q)//直到表尾
{
printf("%d ",q->date);//输出表 / *这里的输出可以定义一个如上例的输出函数
q = q->next;
}
printf("\n");
Destory(&L);//最后销毁表
getche();
}