单链表的创建的代码实现:
链表是线性表的基础部分,它实现了将一组数据从逻辑上按顺序存储从物理上按分布存储的功能。接下来尝试利用C语言对线性表中的链表进行代码实现(此程序中规定用户输入的数据类型为int类型):
typedef struct Node{
int data;
struct Node *next;
}NODE,*PNODE;
首先定义一个结构体,在此结构体中,包含了存储整型数据的数据域,指向下一个结点的指针域。这样一个简单的链表结点就构造完成了。
1、在构造好链表结点后,利用PNODE creat_Hlist();函数实现利用头插法创建链表。
PNODE creat_Hlist(){
int len,i,a;
PNODE s,pHead;
printf("你要输入几个元素?\n");
scanf("%d",&len);
if(len<=0){
printf("你不想输入数据!\n");
}else{
pHead=NULL;
for(i=0;idata=a;
s->next=pHead;
pHead=s;
}
}
}
return pHead;
}
首先声明结构体类型的两个指针变量:s、pHead。之后判断用户想要输入的元素个数,当用户想要输入一定数量的元素后,先将pHead指针变量置空,此时并没有为pHead分配实际存储空间,按照元素个数申请相应数量的空间,此操作由一个循环完成,在每个空间成功申请后将s指针变量指向这个空间,此时为s指针分配了实际的存储空间,将用户输入的第一个元素通过s指针变量存入相应空间结构体的数据域,相应空间的指针域指针指向pHead所指向的空间(此空间在最开始不是物理空间而是null),然后将pHead指向s指针指向的实际存储空间,在存储第二个数据后,第二个数据存储的结构体中的指针域中的指针便指向第一个数据的存储空间,而pHead指针则指向了第二个数据的存储空间;当所有数据存储完毕,此函数返回了pHead指针。因为pHead指针已经指向了最后一个存储元素的空间(在本人看来其实是指向了所有存储元素的空间)。
2、在构造好链表结点后,利用PNODE creat_Tlist();利用尾插法创建链表。
PNODE creat_Tlist(){
int len,i,a;
PNODE pHead,pTail,pNew;
printf("你想输入几个元素?\n");
scanf("%d",&len);
if(len<=0){
printf("你不想输入数据!\n");
}else{
pHead=(PNODE)malloc(sizeof(NODE));
if(pHead==NULL){
printf("存储空间申请失败,请使用头插法输入数据!\n");
}else{
pTail=pHead;
pHead->data='#';
pTail->next=NULL;
for(i=0;idata=a;
pNew->next=NULL;
pTail->next=pNew;
pTail=pNew;
}
}
}
}
return pHead;
}
先声明三个结构体类型指针变量pHead,pTail,pNew。在判断好用户属于合法输入后,将pHead指向第一个实际已经申请好的结构体存储空间(若存储空间申请无效后,那么不能实现尾插法),随后将pTail也指向pHead所指的存储空间,于此同时将第一个存储空间中的数据域中赋值为“#”(之所以这么赋值是因为用于后面对链表操作时和头插法创建的列表进行区分),之后将第一个存储空间将的指针域置空,在存储第一个数据时,利用pNew指向第二个申请的存储空间(若存储空间申请无效后,那么不能实现尾插法),通过pNew指针向存储空间数据域存放目标数据,将存储空间指针域置空,同时将第一个存储空间的指针(利用pTail->next表示)指向pNew指向的第二个存储空间,同时将pTail指针指向pNew指针向的存储空间。随后在合法(用户想要存储的数据个数)长度内,依次申请存储空间,同时利用pNew指针指向这些空间,通过pNew指针分别对存储空间中的数据域进行赋值,同时通过pNew将存储空间的指针域置空。重复之前的操作。最后返回pHead指针。因为pHead指针已经指向了最后一个存储元素的空间(在本人看来其实是指向了所有存储元素的空间)。
3、利用int judge_list();函数判断这个链表是头插法生成还是尾插法生成:
int judge_list(PNODE pHead){
int i;
PNODE p;
p=pHead;
if(p->data=='#'){
i=1;
printf("此链表由尾插法构成\n");
}else{
i=0;
printf("此链表由头插法构成\n");
}
return i;
}
根据头插法和尾插法在头指针处有没有数据对创建好的链表进行头插法和尾插法的判断。若是链表由尾插法构成则函数返回1;反之返回0.
4、由void trave_list();函数进行链表的遍历打印:
void trave_list(PNODE pHead){
int a;
PNODE p;
p=pHead;
if(p==NULL){
printf("这是一个空链表!\n");
}else{
a=judge_list(pHead);
if(a==1){
p=pHead->next;
}
while(p!=NULL){
printf("%4d",p->data);
p=p->next;
}
}
}
首先判断链表是否为空表,其次判断已经生成的链表是由头插法创建还是由尾插法创建,之后依据不同的创建方法对链表进行遍历打印。
5、由int length_list();函数打印链表的长度:
int length_list(PNODE pHead){
int i,a;
i=0;
PNODE p;
p=pHead;
if(p==NULL){
printf("这是一个空表!\n");
}else{
a=judge_list(pHead);
if(a==1){
p=pHead->next;
}
while(p!=0){
i=i+1;
p=p->next;
}
printf("这个链表有%d个数据!\n",i);
}
return i;
}
先判断是否为空表、现有链表由什么方法创建,然后对链表中的元素进行计数。最后返回统计的数字即链表的长度。
6、利用void find_list();函数实现链表数据的查询:
void find_list(PNODE pHead){
int i,a,b;
i=0;
PNODE p;
p=pHead;
if(p==NULL){
printf("这是一个空表!\n");
}else{
a=judge_list(p);
if(a==1){
p=pHead->next;
}
b=length_list(p);
printf("你想查找第几号元素?\n");
scanf("%d",&a);
if(a<=0||a>b){
printf("你查找的元素不在这个链表中!\n");
}else{
while(p!=NULL){
i=i+1;
if(i==a){
printf("第%d号元素是:%4d",a,p->data);
break;
}
p=p->next;
}
}
}
}
在判断链表不是空表后,先判断此链表是用头插法生成还是用尾插法实现,然后通过元素在;链表中的号数来实现对链表中的元素的查询。
7、利用void change_list();/函数实现对链表数据的修改:
void change_list(PNODE pHead){
int i,a,b,c;
i=0;
PNODE p;
p=pHead;
if(p==NULL){
printf("这是一个空表!\n");
}else{
a=judge_list(p);
if(a==1){
p=pHead->next;
}
b=length_list(p);
printf("你想修改第几号元素?\n");
scanf("%d",&a);
if(a<=0||a>b){
printf("你要修改的元素不在这个链表中!\n");
}else{
while(p!=NULL){
i=i+1;
if(i==a){
printf("第%d号元素是:%d ,",a,p->data);
printf("请输入你要修改的值:\n");
scanf("%d",&c);
p->data=c;
printf("元素修改成功!\n");
break;
}
p=p->next;
}
}
}
}
在判断链表不为空后,通过修改链表长度内某号数对应的元素来修改指定位置处的元素值。
8、利用void apend_list();函数实现链表数据的后面插入:
void apend_list(PNODE pHead){
int i,a,b,d;
i=0;
PNODE p,c;
p=pHead;
if(p==NULL){
printf("这是一个空表,请先建立链表!\n");
}else{
a=judge_list(p);
if(a==1){
p=pHead->next;
}
b=length_list(p);
printf("你想在第几号元素后面插入数值?\n");
scanf("%d",&a);
if(a<=0||a>b){
printf("你要插入的位置不在这个链表中!\n");
}else{
while(p!=NULL){
i=i+1;
if(i==a){
c=(PNODE)malloc(sizeof(NODE));
if(c==NULL){
printf("开辟空间失败,无法输入数据!\n");
}else{
printf("请输入你想输入的数值:\n");
scanf("%d",&d);
c->data=d;
c->next=p->next;
p->next=c;
printf("数值插入成功!\n");
}
break;
}
p=p->next;
}
}
}
}
先判断链表是否为空,在不为空且知道链表长度(调用length_list()函数,详见【C语言】单链表的创建(三)部分描述)的前提下:用户输入想要在几号元素(目标元素)后面插入数据,当输入的号数合法之后,在目标元素后面插入数据。
9、利用void befor_list();函数实现链表数据的前面插入:
void befor_list(PNODE pHead){
int i,a,b,d,e;
i=0;
PNODE p,c;
p=pHead;
if(p==NULL){
printf("这是一个空表,请先建立链表!\n");
}else{
e=judge_list(p);
if(e==1){
p=pHead->next;
}
b=length_list(p);
printf("你想在第几号元素前面插入数值?\n");
scanf("%d",&a);
if(a<=0||a>b+1){
printf("你要插入的位置不在这个链表中!\n");
}else{
c=(PNODE)malloc(sizeof(NODE));
if(c==NULL){
printf("开辟空间失败,无法输入数据!\n");
}else{
printf("请输入你想输入的数值:\n");
scanf("%d",&d);
c->data=d;
c->next=NULL;
if(a==1){
printf("此程序无法插入第一个结点,但可以修改第一个结点!\n");
}else{
while(p!=NULL){
i=i+1;
if(i==a-1){
c->next=p->next;
p->next=c;
printf("数值插入成功!\n");
break;
}
p=p->next;
}
}
}
}
}
}
先判断是否为空表,在不为空且知道链表长度(调用length_list()函数,详见【C语言】单链表的创建(三)部分描述)的前提下,然后找到用户输入的合法目标元素号数的前一个号数,在前一个号数的后面实现元数的插入。这也引出一个问题:无法在第一个结点前插入元素。目前本人还没有想法对其进行完善和优化。
10、利用void delet_list();函数实现对链表元素的删除:
void delet_list(PNODE pHead){
int i,a,b,e,f;
i=0;
PNODE p,s;
p=pHead;
if(p==NULL){
printf("这是一个空表!\n");
}else{
e=judge_list(p);
if(e==1){
p=pHead->next;
}
b=length_list(p);
printf("你想删除第几号元素?\n");
scanf("%d",&a);
if(a<=0||a>b){
printf("你删除的元素不在这个链表中!\n");
}else{
if(a==1){
printf("此程序无法删除第一个结点,但可以修改第一个结点!\n");
}else{
while(p!=NULL){
i=i+1;
if(i==a-1){
s=p->next;
f=s->data;
p->next=p->next->next;
free(s);
printf("第%d号元素:%d 删除成功!\n",a,f);
break;
}
p=p->next;
}
}
}
}
}
在判断链表不为空后,找到用户想要删除的元素的前面一个元素,修改其指针域中指针指向的内容即可将目标元素删除,同时不要忘记将指向目标元素的指针释放。
11、现在就来实现应用一个基本框架将这些基本功能串联起来,构成一个简单的单链表小程序。因此单链表系列在此做一个小完结。基本框架如下(和之前创建顺序表的框架相似):
#include
#include
#include //引入函数库
typedef struct Node{
int data;
struct Node *next;
}NODE,*PNODE; //定义结构体
//声明各个功能函数
void main(){
int b=1,c;
PNODE pHead;
pHead=NULL;
while(b){
system("cls");
printf("\n\n\t\t线性表之单链表的基本操作\n\n");
printf("\t\t...1-n.链表的各种功能操作; \n");
printf("\t\t...0 退出 \n");
printf("\n\t\t请选择 [0,10]: ");
scanf("%d",&c);
printf("\n\n");
switch(c){
case 1-n:调用各种功能函数 ;break;
case 0:b=0 ;break;
}
if(c!=0){
printf("\n 输入然后关键字继续...");
getche();
}
}
system("cls");
printf("\t\t 程序!\n");
exit(-1);
}
//具体的各种功能函数
单链表的运行结果:
1.程序开始运行界面:
2.由头插法创建链表:
3.对链表进行遍历打印(顺便判断链表生成方式)
4.对链表进行后插入:
打印插入数值后的链表状态:
5.删除元素:
打印删除元素后链表状态:
6.在链表中前插入数据:
打印插入数据后的链表状态:
7.尾插法生成链表:
输出新生成的链表:
在此仅仅展示这几个简单功能,剩余功能也能正常实现。本程序的不足之处在于部分代码显得过于冗余,另外在每一次进行新操作之前还要判断生成方法是“头插法”还是“尾插法”才能做相应处理,这使得第一个结点的操作不同于其他结点,在此本人暂时没有想到更好的解决方法(摆烂先)
以上是本人对链表的C语言代码初步实现,不喜勿喷,感谢理解。
相关链接:
【C语言】顺序表的创建_lixxkv的博客-CSDN博客