C语言中有关链表的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言中有关链表的问题相关的知识,希望对你有一定的参考价值。

下面的程序:(建立一个有n个节点的环形链表并输出)
#include<stdio.h>
#include<stdlib.h>
#define len sizeof(struct person)
struct person
int num;
struct person *next;
*p1,*p2,*head=0;
main()
int i,n;
scanf("%d",&n);
p2=head=(struct person *)malloc(len);
p2->num=1;
for(i=2;i<=n;i++)
p1=(struct person *)malloc(len);
p1->num=i;
p2->next=p1;
p2=p1;

p1->next=head;
for(p1=head;p1<head+n;p1++)
printf("%d ",p1->num);
printf("\n");

我希望得到的是:第n个节点处,num的值为n!
TC下单步执行,观察变量p1->num是正确的,可是为什么到最后输出接点处num的值就错了。比如,输入5,输出的却是:1 9 2 9 3。如果我把:
for(p1=head;p1<head+n;p1++)
printf("%d ",p1->num);
改为:for(p1=head;p1<head+2*n;p1+=2)
printf("%d ",p1->num);

输出的就是:1 2 3 4 5
我还试了不建成环形链表,把生成链表时的p1->next=head;去掉,结果还是一样的!明明只有n个节点呀!
请问各位,这个是怎么回事,哪里有问题,或者请大家解释下这种情况的出现,谢谢啦!!!

for(p1=head;p1<head+n;p1++)
printf("%d ",p1->num);
这步有点问题。
其中p1++隐含的假设是链表所有元素是像数组一样在内存中连续存放的。
但是按照前面的代码,所有元素的内存是通过malloc动态分配的,因此p1++并不能移动到下一个元素处。
并且,既然是链表的实现,应该充分利用链表的next指针。
可以重写如下:
p1=head;
for(i=0;i<n;++i)

printf("%d ",p1->num);
p1=p1->next;
参考技术A #include<stdio.h>
#include<stdlib.h>
#define len sizeof(struct person)
struct person
int num;
struct person *next;
*p1,*p2,*head=NULL;
main()

int i,n;
scanf("%d",&n);
head=(struct person *)malloc(len);
p2=head;
p2->num=1;
p2->next = NULL;
for(i=2;i<=n;i++)

p1 = (struct person *)malloc(len);
p1->num=i;
p1->next = NULL;
p2->next=p1;
p2=p1;

//p1->next=head;
for(p1=head;p1!=NULL;p1=p1->next)
//注意这里的循环,p1++这里写的不对
printf("%d ",p1->num);
printf("\n");

C语言链表问题

哪位大哥告诉我怎样实现:
链表的插入
链表的删除
链表的排序。

请大哥们帮我写一下语句,最好能讲解一下,小弟高分送上

#include
#include
#define NULL 0
#define LEN sizeof(struct student)
struct student

long num; /*学号*/
float score; /*分数,其他信息可以继续在下面增加字段*/
struct student *next; /*指向下一节点的指针*/
;
int n; /*节点总数*/
/*
==========================
功能:创建节点
返回:指向链表表头的指针
==========================
*/
struct student *Create()

struct student *head; /*头节点*/
struct student *p1=NULL; /*p1保存创建的新节点的地址*/
struct student *p2=NULL; /*p2保存原链表最后一个节点的地址*/
n = 0; /*创建前链表的节点总数为0:空链表*/
p1 = (struct student *)malloc(LEN); /*开辟一个新节点*/
p2 = p1; /*如果节点开辟成功,则p2先把它的指针保存下来以备后用*/
if (p1 == NULL) /*节点开辟不成功*/

printf("\nCann't create it, try it again in a moment!\n");
return NULL;

else /*节点开辟成功*/

head = NULL; /*开始head指向NULL*/
printf("Please input %d node -- num,score: ",n+1);
scanf("%ld,%f",&(p1->num),&(p1->score)); /*录入数据*/

while(p1->num != 0) /*只要学号不为0,就继续录入下一个节点*/

n += 1; /*节点总数增加1个*/
if (n==1) /*如果节点总数是1,则head指向刚创建的节点p1*/

head = p1;
/*
注意:
此时的p2就是p1,也就是p1->next指向NULL。
这样写目的是与下面else保持一致。
*/
p2->next = NULL;

else

p2->next = p1; /*指向上次下面刚开辟的节点*/

p2 = p1; /*把p1的地址给p2保留,然后p1去产生新节点*/

p1 = (struct student *)malloc(LEN);
printf("Please input %d node -- num,score: ",n+1);
scanf("%ld,%f",&(p1->num),&(p1->score));

p2->next = NULL; /*此句就是根据单向链表的最后一个节点要指向NULL*/
free(p1); /*释放p1。用malloc()、calloc()的变量都要free()*/
p1 = NULL; /*特别不要忘记把释放的变量清空置为NULL,否则就变成"野指针",即地址不确定的指针。*/
return head; /*返回创建链表的头指针*/

/*
===========================
功能:输出节点
返回: void
===========================
*/
void Print(struct student *head)

struct student *p;
printf("\nNow , These %d records are:\n",n);
p = head;
if(head != NULL) /*只要不是空链表,就输出链表中所有节点*/

printf("head is %o\n", head); /*输出头指针指向的地址*/
do

/*
输出相应的值:当前节点地址、各字段值、当前节点的下一节点地址。
这样输出便于读者形象看到一个单向链表在计算机中的存储结构,和我们
设计的图示是一模一样的。
*/
printf("%o %ld %5.1f %o\n", p, p->num, p->score, p->next);
p = p->next; /*移到下一个节点*/

while (p != NULL);


/*
==========================
功能:删除指定节点
(此例中是删除指定学号的节点)
返回:指向链表表头的指针
==========================
*/
/*
单向链表的删除图示:
---->[NULL]
head
图3:空链表
从图3可知,空链表显然不能删除
---->[1]---->[2]...---->[n]---->[NULL](原链表)
head 1->next 2->next n->next
---->[2]...---->[n]---->[NULL](删除后链表)
head 2->next n->next
图4:有N个节点的链表,删除第一个节点
结合原链表和删除后的链表,就很容易写出相应的代码。操作方法如下:
1、你要明白head就是第1个节点,head->next就是第2个节点;
2、删除后head指向第2个节点,就是让head=head->next,OK这样就行了。
---->[1]---->[2]---->[3]...---->[n]---->[NULL](原链表)
head 1->next 2->next 3->next n->next
---->[1]---->[3]...---->[n]---->[NULL](删除后链表)
head 1->next 3->next n->next
图5:有N个节点的链表,删除中间一个(这里图示删除第2个)
结合原链表和删除后的链表,就很容易写出相应的代码。操作方法如下:
1、你要明白head就是第1个节点,1->next就是第2个节点,2->next就是第3个节点;
2、删除后2,1指向第3个节点,就是让1->next=2->next。
*/
struct student *Del(struct student *head, long num)

struct student *p1; /*p1保存当前需要检查的节点的地址*/
struct student *p2; /*p2保存当前检查过的节点的地址*/
if (head == NULL) /*是空链表(结合图3理解)*/

printf("\nList is null!\n");
return head;

/*定位要删除的节点*/
p1 = head;
while (p1->num != num && p1->next != NULL) /*p1指向的节点不是所要查找的,并且它不是最后一个节点,就继续往下找*/

p2 = p1; /*保存当前节点的地址*/
p1 = p1->next; /*后移一个节点*/

if (num == p1->num) /*找到了。(结合图4、5理解)*/

if (p1 == head) /*如果要删除的节点是第一个节点*/

head = p1->next; /*头指针指向第一个节点的后一个节点,也就是第二个节点。这样第一个节点就不在链表中,即删除。*/

else /*如果是其它节点,则让原来指向当前节点的指针,指向它的下一个节点,完成删除*/

p2->next = p1->next;

free(p1); /*释放当前节点*/
p1 = NULL;
printf("\ndelete %ld success!\n",num);
n -= 1; /*节点总数减1个*/

else /*没有找到*/

printf("\n%ld not been found!\n",num);

return head;

/*
==========================
功能:插入指定节点的后面
(此例中是指定学号的节点)
返回:指向链表表头的指针
==========================
*/
/*
单向链表的插入图示:
---->[NULL](原链表)
head
---->[1]---->[NULL](插入后的链表)
head 1->next
图7 空链表插入一个节点
结合原链表和插入后的链表,就很容易写出相应的代码。操作方法如下:
1、你要明白空链表head指向NULL就是head=NULL;
2、插入后head指向第1个节点,就是让head=1,1->next=NULL,OK这样就行了。
---->[1]---->[2]---->[3]...---->[n]---->[NULL](原链表)
head 1->next 2->next 3->next n->next
---->[1]---->[2]---->[x]---->[3]...---->[n]---->[NULL](插入后的链表)
head 1->next 2->next x->next 3->next n->next
图8:有N个节点的链表,插入一个节点(这里图示插入第2个后面)
结合原链表和插入后的链表,就很容易写出相应的代码。操作方法如下:
1、你要明白原1->next就是节点2,2->next就是节点3;
2、插入后x指向第3个节点,2指向x,就是让x->next=2->next,1->next=x。
*/
struct student *Insert(struct student *head, long num, struct student *node)

struct student *p1; /*p1保存当前需要检查的节点的地址*/
if (head == NULL) /*(结合图示7理解)*/

head = node;
node->next = NULL;
n += 1;
return head;

p1 = head;
while (p1->num != num && p1->next != NULL) /*p1指向的节点不是所要查找的,并且它不是最后一个节点,继续往下找*/

p1 = p1->next; /*后移一个节点*/

if (num == p1->num) /*找到了(结合图示8理解)*/

node->next = p1->next; /*显然node的下一节点是原p1的next*/
p1->next = node; /*插入后,原p1的下一节点就是要插入的node*/
n += 1; /*节点总数增加1个*/

else

printf("\n%ld not been found!\n",num);

return head;

/*
==========================
功能:反序节点
(链表的头变成链表的尾,链表的尾变成头)
返回:指向链表表头的指针
==========================
*/
/*
单向链表的反序图示:
---->[1]---->[2]---->[3]...---->[n]---->[NULL](原链表)
head 1->next 2->next 3->next n->next
[NULL]next 2->next 3->next n->next head
图9:有N个节点的链表反序
结合原链表和插入后的链表,就很容易写出相应的代码。操作方法如下:
1、我们需要一个读原链表的指针p2,存反序链表的p1=NULL(刚好最后一个节点的next为NULL),还有一个临时存储变量p;
2、p2在原链表中读出一个节点,我们就把它放到p1中,p就是用来处理节点放置顺序的问题;
3、比如,现在我们取得一个2,为了我们继续往下取节点,我们必须保存它的next值,由原链表可知p=2->next;
4、然后由反序后的链表可知,反序后2->next要指向1,则2->next=1;
5、好了,现在已经反序一个节点,接着处理下一个节点就需要保存此时的信息:
p1变成刚刚加入的2,即p1=2;p2要变成它的下一节点,就是上面我们保存的p,即p2=p。
*/
struct student *Reverse(struct student *head)

struct student *p; /*临时存储*/
struct student *p1; /*存储返回结果*/
struct student *p2; /*源结果节点一个一个取*/
p1 = NULL; /*开始颠倒时,已颠倒的部分为空*/
p2 = head; /*p2指向链表的头节点*/
while (p2 != NULL)

p = p2->next;
p2->next = p1;
p1 = p2;
p2 = p;

head = p1;
return head;

/*
以上函数的测试程序:
提示:根据测试函数的不同注释相应的程序段,这也是一种测试方法。
*/
main()

struct student *head;
struct student *stu;
long thenumber;
/* 测试Create()、Print()*/
head = Create();
Print(head);
/*测试Del():请编译时去掉注释块*/
/*
printf("\nWhich one delete: ");
scanf("%ld",&thenumber);
head = Del(head,thenumber);
Print(head);
*/
/*测试Insert():请编译时去掉注释块*/
/*
stu = (struct student *)malloc(LEN);
printf("\nPlease input insert node -- num,score: ");
scanf("%ld,%f",&stu->num,&stu->score);
printf("\nInsert behind num: ");
scanf("%ld",&thenumber);
head = Insert(head,thenumber,stu);
free(stu);
stu = NULL;
Print(head);
*/
/*测试Reverse():请编译时去掉注释块*/
/*
head = Reverse(head);
Print(head);
*/
printf("\n");
system("pause");
参考技术A #include <stdio.h>
#include <stdlib.h>
const int MAX_NAME_LEN = 100;
struct Node

int id;
char name[MAX_NAME_LEN];
char sex[10];
int age;
struct Node * next;
;
/*
获取一个新的节点,数据从控制台输入

返回新节点的一个指针
*/
struct Node* getNewNode()

struct Node * node = (struct Node*)malloc(sizeof(struct Node));

printf("学号:");
scanf("%d",&node->id);

printf("姓名:");
scanf("%s",&node->name);

printf("性别:");
scanf("%s",&node->sex);

printf("年龄:");
scanf("%d",&node->age);

node->next = NULL;

return node;

/*
比较两个节点的大小(可以根据需要定制)
这里是根据学号(id)比较的

节点 a 大于节点 b ,返回一个大于 0 的数
节点 a 等于节点 b ,返回 0
节点 a 小于节点 b ,返回一个小于 0 的数
*/
int compareNode(struct Node* a , struct Node* b)

return (a->id) - (b->id);


/*
判断两个节点是否相等(可以根据需要定制)
这里只要年龄相等,就认为相等

节点 a 等于节点 b ,返回 0
节点 a 不等于节点 b ,返回一个不等于 0 的数
*/
int isEqualNode(struct Node* a , struct Node* b)

return (a->age) == (b->age);


/*输出节点*/
void printNode(struct Node* node)

printf("学号:%d\n",node->id);
printf("姓名:%s\n",node->name);
printf("性别:%s\n",node->sex);
printf("年龄:%d\n",node->age);
printf("\n");

/*
在链表 list 中按顺序插入新节点 newNode

返回新插入的节点的一个指针
*/
struct Node* insertNodeInList(struct Node** list,struct Node * newNode)

struct Node * p,*q;
if(*list == NULL)

*list = newNode;

else

// q 指向 p 的前一个节点
q = NULL;
p = *list;

while(p != NULL)

// 如果 p 指向的节点的数据不小于新申请的节点的 data
// 新申请的节点插入到 p 之前
if(compareNode(newNode,p) < 0)

if(p == *list)

newNode->next = *list ;
*list = newNode;

else

newNode->next = p;
q->next = newNode;

break;


// 否则,移动到下一个节点
else

q = p;
p = p->next;



// 新申请的节点需要插入到末尾
if(p == NULL)

q ->next = newNode;



return newNode;

/*
获取一个有 n 个节点的新链表

返回这个新链表的指针
*/
struct Node* getNewList(int n)

struct Node * head = NULL;
struct Node * newNode;
int i;

// 读入节点内容,并按顺序插入
for(i=0;i<n;i++)

// 新申请一个节点
printf("**** 输入第 %d 个学生信息 ****\n",i+1);
newNode = getNewNode();
// 插入新节点
insertNodeInList(&head,newNode);


return head;

/*
从链表 list 中删除和 deleteNode 相等的节点

返回删除了的节点个数
*/
int deleteNodeInList(struct Node** list,struct Node * deleteNode)

// q 指向 p 的前一个节点
struct Node *q = NULL ,*p = *list;
int deleteNodeNum = 0;
while(p != NULL)

// 找到和要删除的节点匹配的节点
if(isEqualNode(p,deleteNode))

// 要删除头节点,特殊处理
if(p == *list)

*list = p->next;
free(p);
p = *list;


// 要删除其他节点
else

q->next = p->next;
free(p);
p = q->next;


// 统计删除了的节点个数
deleteNodeNum ++;

else

q = p ;
p = p -> next;



return deleteNodeNum;


/*
统计链表 list 中的节点个数

返回链表中节点个数
*/
int getNodeNumInList(struct Node* list)

struct Node * p = list;
int counter = 0;

while(p != NULL)

counter ++;
p = p->next;


return counter;


/*打印链表*/
void printList(struct Node* list)

struct Node * p = list;
printf("\n********* 学生信息 *********\n");

while(p != NULL)

printNode(p);
p = p->next;

printf("一共有 %d 个学生。\n",getNodeNumInList(list));
printf("\n****************************\n");


/*销毁链表*/
void destroyList(struct Node* list)

struct Node * p,*q;
q = list;
p = list -> next;

while(q != NULL)

free(q);
q = p;
if(p!=NULL)

p = p->next;




int main(int argc, char *argv[])

// 新建一个有 10 个节点的链表
struct Node* list = getNewList(10);
struct Node deleteNode;
// 显示链表
printList(list);

// 输入要删除的年龄
// 当链表不为空,一直可以输入要删除的年龄
// 如果输入的年龄小于 0 ,退出
printf("输入要删除的学生年龄:");
while( getNodeNumInList(list) > 0 && scanf("%d",&deleteNode.age) != EOF && deleteNode.age >=0 )

// 删除节点
printf("删除了 %d 个学生。\n",deleteNodeInList(&list,&deleteNode));
// 显示链表
printList(list);
if(getNodeNumInList(list) > 0)

printf("输入要删除的学生年龄:");



return 0;
参考技术B typedef struct MESSAGE

unsigned int ID;
char *name,*address,*postnum,*telephone;
struct MESSAGE *next;
Message;
Message *TailMessage(Message *find)

while(find->next!=NULL)

find=find->next;

return find;


Message *InitMessage()

Message *returnvar;
if((returnvar=(Message*)malloc(sizeof(Message)))==NULL)return NULL;
returnvar->ID=0;
returnvar->name="";
returnvar->address="";
returnvar->postnum="";
returnvar->telephone="";
returnvar->next=NULL;


int InsertMessage(Message *find,unsigned int id,char *name,char *address,char *postnum,char *telephone)

Message *node;
if((node=(Message*)malloc(sizeof(Message)))==NULL)return 0;
node->ID=id;
node->name=name;
node->address=address;
node->postnum=postnum;
node->telephone=telephone;
node->next=find->next;
find->next=node;
return 1;


int DeleteMessage(Message *find,unsigned int id)

Message *freevar;
int returnvar=0;
while(find->next!=NULL)

if(find->next->ID==id)

freevar=find->next;
free(freevar->name);
free(freevar->address);
free(freevar->postnum);
free(freevar->telephone);
find->next=find->next->next;
free(freevar);
returnvar++;

else

find=find->next;


return returnvar;


int DeleteAll(Message *find)

Message *freevar;
int returnvar=0;
while(find->next!=NULL)

freevar=find->next;
free(freevar->name);
free(freevar->address);
free(freevar->postnum);
free(freevar->telephone);
find->next=find->next->next;
free(freevar);
returnvar++;

return returnvar;


int UpDataMessage(Message *find,unsigned int id,char *name,char *address,char *postnum,char *telephone)

int returnvar=0;
for(find=find->next;find!=NULL;find=find->next)

if(find->ID==id)

free(find->name);
find->name=name;
free(find->address);
find->address=address;
free(find->postnum);
find->postnum=postnum;
free(find->telephone);
find->telephone=telephone;
returnvar++;


return returnvar;


int SelectMessage(Message *find,unsigned int id)

int returnvar=0;
find=find->next;
while(find!=NULL)

if(find->ID==id)

printf("<%s ID=%d address=%s postnum=%s telephone=%s />\n",find->name,find->ID,find->address,find->postnum,find->telephone);
returnvar++;

find=find->next;

return returnvar;


int SelectAll(Message *find)

int returnvar=0;
find=find->next;
while(find!=NULL)

printf("<%s ID=%d address=%s postnum=%s telephone=%s />\n",find->name,find->ID,find->address,find->postnum,find->telephone);
returnvar++;
find=find->next;

return returnvar;


int SaveMessage(Message *find,char *path)

FILE *fsave;
if((fsave=fopen(path,"w"))==NULL)

return 0;

find=find->next;
while(find!=NULL)

fprintf(fsave,"%s\t%s\t%s\t%s\n",find->name,find->address,find->postnum,find->telephone);
find=find->next;

fclose(fsave);
return 1;


unsigned int LoadMessage(Message *find,unsigned int id,char *path)

Message *TailMessage(Message *find);
int InsertMessage(Message *find,unsigned int id,char *name,char *address,char *postnum,char *telephone);
FILE *fload;
char charvar,str[DATALEN*5],*name,*address,*postnum,*telephone;
int index,bottom;
index=bottom=0;
if((fload=fopen(path,"r"))==NULL)

return 1;

while((charvar=fgetc(fload))!=EOF)

if(charvar=='\n')

str[index]='\0';
bottom=index=0;
if((name=(char*)malloc(sizeof(char)*DATALEN))==NULL)return 0;
while(str[bottom]!='\t')

name[bottom-index]=str[bottom];
bottom++;

name[bottom-index]='\0';
bottom=index=bottom+1;
if((address=(char*)malloc(sizeof(char)*DATALEN))==NULL)return 0;
while(str[bottom]!='\t')

address[bottom-index]=str[bottom];
bottom++;

address[bottom-index]='\0';
bottom=index=bottom+1;
if((postnum=(char*)malloc(sizeof(char)*DATALEN))==NULL)return 0;
while(str[bottom]!='\t')

postnum[bottom-index]=str[bottom];
bottom++;

postnum[bottom-index]='\0';
bottom=index=bottom+1;
if((telephone=(char*)malloc(sizeof(char)*DATALEN))==NULL)return 0;
while(str[bottom])

telephone[bottom-index]=str[bottom];
bottom++;

telephone[bottom-index]='\0';
if(InsertMessage(TailMessage(find),id,name,address,postnum,telephone)!=NULL)

id++;

index=0;

else

str[index]=charvar;
index++;


free(str);
fclose(fload);
return id;

/*一个通讯录,增删改差都有,分析下,不懂的话追问*/
参考技术C 到网上搜索一下就可以了。这问题太简单了。

以上是关于C语言中有关链表的问题的主要内容,如果未能解决你的问题,请参考以下文章

C语言链表的问题

c语言对链表的数据排序的问题,分不是问题!

c语言关于链表的一道题

C语言实现链表的逆序打印

C语言链表问题

C语言链表的建立?