链式存储结构:是指把数据元素存放在任意内存未被占用的存储单元里,这组存储单元可以是连续的,也可以是不连续的。
大概就是这样:
因此,为了表示每个数据元素a1,与其直接后继数据元素 a2 之间的逻辑关系,对数据元素a来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。
对此有如下几个概念:
数据域 | 指针域 | 指针(链) | 头指针 |
---|---|---|---|
存储数据元素信息的域 | 存储直接后继位置的域 | 指针域中存储的信息 | 指向第一个结点的指针,具有标识作用常冠以链表名字,是链表的必要元素 |
结点 | 链表 | 单链表 | 头结点 |
---|---|---|---|
数据域与指针域的结合 | n 个结点按一定逻辑次序的链结 | 链表的每个结点中只包含一个指针域 | 放在第一元素结点之前,数据域一般无意义,非必要 |
完整代码下载地址:https://download.csdn.net/download/luotuoxiansheng/10756421
typedef struct SlNode
{
ElemType1 name[DATA1LENGTH]; //创建数组存储空间
ElemType2 number[DATA2LENGTH];
ElemType2 length; //标识表长
struct SlNode *next; //创建指向结点的指针
}SlNode,*LinkList;
创建结点数据并利用尾插法依次插入链表,形成初始的单链表
示例代码:
void CreateList(SlNode *L)
{
SlNode *p,*newnode;
L->length=0;
p=L;
char flag='y';
puts("创建表单:");
while(flag=='Y'||flag=='y'){
newnode=(LinkList)malloc(sizeof(SlNode));
printf("name:");
scanf("%s",newnode->name);
printf("number:");
scanf("%d",newnode->number);
//节点插入(尾部)
newnode->next=NULL;
p->next=newnode;
p=newnode;
L->length++;
getchar();//等待输入完成后的回车键
printf("继续输入?(y/n)");
scanf("%c",&flag);
}
}
void SListInsert(SlNode *L)
{
int i;
int j=1,n=1;
SlNode *p,*newnode;
p=L;
printf("在第几个位置插入?请输入:");
scanf("%d",&i);
if (i>(L->length+1)||inext;
j++;
}
//找到插入位置后创建结点数据
newnode=(LinkList)malloc(sizeof(SlNode));
printf("name: ");
scanf("%s",newnode->name);
printf("number: ");
scanf("%d",newnode->number);
//插入
newnode->next=p->next;
p->next=newnode;
if(i==L->length+1)//如果是在尾部插入,则让newnode->next=NULL;
newnode->next=NULL;
L->length++;
}
结果演示:
可在任意位置插入结点。依次在尾部、头部、第i个结点处插入:
尾插:
头插:
第3个结点处:
Status SListDelete(SlNode *L)
{
int j=1;
int i;
SlNode *p=L;
SlNode *q;
printf("请输入Nob:");
scanf("%d",&i);
if (i>(L->length)||inext;
j++;
}
//删除q节点
q=p->next;
p->next=q->next;
free(q);
--(L->length);
return 1;
}
Status SListUpdate(SlNode *L)
{
int j=1;
int i;
SlNode *p=L->next;
printf("请输入Nob:");
scanf("%d",&i);
if (i>(L->length)||inext;
j++;
}
printf("新name:");
scanf("%s",p->name);
printf("新number:");
scanf("%d",p->number);
return 1;
}
本例程中若要查找字符串类型的数据,在c语言中应使用strcmp()函数去匹配查找,不能直接使用“==”匹配,笔者因为这个问题在这出现了很多错误。
示例代码:
SlNode *SListGet(SlNode *L)
{
int n;
ElemType2 Nob;
int ch;
SlNode *p;
SlNode *input;
SlNode *get;
p=L->next;
input=(LinkList)malloc(sizeof(SlNode));//创建结点用于存储输入数据
printf("查找项(1.Nob/2.name/3.number):");
scanf("%d",&ch);
switch(ch)
{
case 1:{
printf("请输入Nob:");
scanf("%d",&Nob);
n=1;
while(n<=L->length)
{
if(Nob==n)
{
get=p;
return get;
}
p=p->next;
n++;
}
printf("没有此数据!\n");return 0;
};break;
case 2:{
n=1;
printf("请输入name:");
scanf("%s",input->name);
while(n<=L->length)
{
if(!strcmp(p->name,input->name))//若两个字符串相等
{
get=p;
return get;//找到就返回
}
p=p->next;
n++;
}
printf("没有此数据!\n");return 0;
};break;
case 3:{
n=1;
printf("请输入number:");
scanf("%d",input->number);
while(n<=L->length)
{
if(*p->number==*input->number)
{
get=p;
return get;//找到就返回
}
p=p->next;
n++;
}
printf("没有此数据!\n");return 0;
};break;
default: printf("错误!没有这个选项!\n");
}
}
结果演示:
按序号查找:
按name查找:
按number查找:
排序方法多种多样,有两篇博文对各种排序方法都有不错的介绍和实现:
https://www.cnblogs.com/eniac12/p/5329396.html#s1
https://www.cnblogs.com/eniac12/p/5332117.html
在单链表中使用冒泡排序关键在于相邻两个结点的交换:
交换后p往后退一格:
示例代码:
void SListSort(SlNode *L)
{
int i,j;
SlNode *pre=L;
SlNode *p=L->next;
SlNode *tmp;
for (i=0;ilength-1;i++)
{
pre=L;
p=L->next;
for (j=0;jlength-1-i;j++)
{
if (*(p->number)>*(p->next->number))
{
//交换节点
pre->next=p->next;
p->next = p->next->next;
pre->next->next=p;
p=pre->next;//更新p的位置
}
//p再前进一个结点
p=p->next;
pre=pre->next;
}
}
PrintList(L);//打印表单
}
表单打印和清空整表的内容不再详细写出,详见完整代码,下载地址:https://download.csdn.net/download/luotuoxiansheng/10756421
比较顺序表,单链表更加灵活,且存储空间大小不确定。若需要频繁插入和删除时适合使用单链表,以及当线性表中的元素个数变化较大或者根本不知道有多大时宜采用单链表结构。
以上就是对单链表的学习和分享