前面一段时间学习了数据结构,一直都以为数据结构中链表是比较难的,以至于在学校考试的时候直接挂科了,这次再学就感觉老师讲起来还是比较简单的,下面简单总结一下!
数据存储的方式有很多钟,链表便是其中之一。但是,链表又是如何存储数据的呢?
我们知道,我们在定义数组时系统会给数组分配一段连续空间,比如定义一个有10个整型变量的数组arr,int arr[10];,系统就会在内存中给arr分配10个连续的整型的空间,也就是物理上连续,当然逻辑上也是连续的,这样就会导致一个问题,假设我需要定义一个数组,里面存了10000个整型变量,但是内存又没有连续的10000个整型空间,那咋办呢?
这个时候就需要用到链表了,链表存储的数据也是逻辑上连续的,但是,这些在物理上(也就是在内存中)并不是连续的,那我们应该怎么做才能实现呢?
用指针!!!,那这样的话,就需要定义结构体,一个成员用来存储数据,也就是数据域,另一个成员用来保存下一个结构体的地址,也就是指针域,这样我们只需要知道第一个结构体的地址就可以找到后面所有结构体的地址,而知道结构体的地址就能取出其数据域中的数据,这样不就实现了在内存中不连续了嘛,只要知道地址就行。
链表又分几种,分别是单向链表,单向循环链表,双向链表,双向循环链表,内核链表。我们今天就来一起学习一下----单向链表。
- 单向链表模型
本质为一个一个结构体通过指针在内存中相连接,结构体定义为:
typedef struct LINK
{
int data;//数据域
struct Link *next;//指针域
}link;//取别名为link
画个图吧!更直观,如图1.1
图1.1 单向链表模型
- 单向链表程序实现(有点多,希望大家耐心看完哈!)
2.1. 头文件link.h
#ifndef _LINK_H_
#define _LINK_H_
#include <stdio.h>
#include <stdlib.h>
typedef struct LINK
{
int data;
struct LINK *next;
}link;
extern link *link_init(void);//链表初始化
extern void link_insert_head(link* head,int num);//头插
extern void show(link *head);//遍历打印出链表中数据
extern void link_insert_tail(link* head,int num);//尾插
extern int link_del(link *head,int num);//删除结点
extern int link_search(link *head,int num);//查找链表中数据
extern void link_change(link *head,int num,int newnum);//改变链表中数据
#endif
2.2. 功能函数link.c
#include "link.h"
/**************************************
/*作用:初始化链表
/*参数:无
/*返回值:新建头结点的地址
**************************************/
link *link_init(void)
{
link *p=(link *)malloc(sizeof(link));//申请堆空间
p->next=NULL;将头结点的指针指向NULL
return p;
}
/**************************************
/*作用:在头结点后插入一个新结点,简称头插
/*参数:头结点地址,插入结点的数据
/*返回值:无
**************************************/
void link_insert_head(link* head,int num)
{
link *p=(link *)malloc(sizeof(link));//申请一个新结点
p->data=num;//给数据域赋值
p->next=head->next;//指来指去,将新建结点的指针指向头结点指针指向的结点
head->next=p;//将头结点指针指向新建结点
}
/**************************************
/*作用:打印链表中数据
/*参数:头结点的地址
/*返回值:无
**************************************/
void show(link *head)
{
link *temp=head->next;//定义一个指针指向头结点的下一个结点
while(temp !=NULL)
{
printf("%d ",temp->data);
temp=temp->next;//每打印一次之后,temp往后移一个
}
printf("\n");
}
/**************************************
/*作用:在末尾插入一个新结点,简称尾插
/*参数:头结点地址,插入结点的数据
/*返回值:无
**************************************/
void link_insert_tail(link* head,int num)
{
link *node=(link *)malloc(sizeof(link));
node->data=num;
link *temp=head;
while(temp->next!= NULL)//需要先定位到最后一个结点
{
temp=temp->next;
}
node->next=NULL;
temp->next=node;
}
/**************************************
/*作用:删除某个数据
/*参数:头结点地址,需要删除的数据
/*返回值:成功返回0,失败返回-1
**************************************/
int link_del(link *head,int num)
{
link *temp=head;
link *p;
while(temp != NULL)
{
if(temp->next->data == num)//遍历找到删除数据的结点
{
break;
}
temp=temp->next;
}
if(temp==NULL)
{
return -1;//如果未找到,返回-1
}
else
{
p=temp->next;
temp->next=p->next;//删除结点只需将被删除结点的前一个结点的指针指向其的后一个结点就行
free(p);//将需要被删除的结点空间释放
return 0;
}
}
/**************************************
/*作用:查询某个数据的位置
/*参数:头结点地址,需要查询的数据
/*返回值:返回位置n
**************************************/
int link_search(link *head,int num) // 4 3 2 1 6 7 8 num=2
{
link *temp=head->next;
int n=1;
while(temp->next != NULL)
{
if(temp->data == num)
{
break;
}
temp=temp->next;
n++;//n表示位置
}
return n;
}
/**************************************
/*作用:修改某个数据为新的数据
/*参数:头结点地址,需要修改的数据,新数据
/*返回值:无
**************************************/
void link_change(link *head,int num,int newnum) //4 3 2 1 6 7 8 num=2 newnum=20
{
int add=link_search(head,num);
link *temp=head;
int i;
for(i=0;i<add;i++)
{
temp=temp->next;
}
temp->data=newnum;//替换数据域
}
希望能对大家有所帮助哈!