c语言双向链表链表free的时候出错

C语言通讯录(双向链表实现)管理系统 - 项目源码 - C语言入门|C语言教程|C语言编程软件|C语言训练|C语言比赛|C语言工作-C语言网
C语言通讯录(双向链表实现)管理系统
纯C语言VC6环境实现通讯录系统,亦可以改为XXX信息管理系统可键盘操作界面截图如下:源码如下: ****************************************
纯C语言VC6环境实现通讯录系统,亦可以改为XXX信息管理系统
可键盘操作
界面截图如下:
源码如下:&
/***********************************************************************************************************/
/*程序采用双向循环链表结构,来满足目录可以满足自由上下过渡,遍历的需求.头结点用来表示当前通讯录的人数等信息
/*程序有添加,查询,浏览的功能,基本满足通讯录的要求.
/*程序最大特点是主菜单,用户列表以及每个结点的操作属性菜单均采用上W-A-S-D才选择,回车确认
/*程序核心功能有search()动态搜索函数,creat()创建函数,list()浏览函数构成
/***********************************************************************************************************/
#include&stdio.h&
#include&stdlib.h&
#include&conio.h&
#include&windows.h&
#include&string.h&
//=======================================================================================
#define LENTH 20
char path[20]="d:\\通讯录.txt";
//-------------------------------------------------------------------------------
typedef struct person
//结构体属性
count[10];
char name[LENTH];
char number[LENTH];
//电话号码
struct person *
//前驱指针
struct person *
//后继指针
void control(int x,int p);
void list();
void faceopration(char a[][60],int w);
void opration(int x);
void controlmain(int x);
//----------------------------------------------------------------------------------
node *head=NULL;
//全局变量-头节点
//===================================================================================
void check()
//自检函数
p-&count[1]=' ';
p-&count[2]=' ';
// p-&number[LENTH-2]=' ';
// p-&number[LENTH-3]=' ';
if(p-&next)
}while(p-&next && p-&next!=head-&next);
if(head-&next)
p-&count[1]=16;
p-&count[2]=16;
// p-&number[LENTH-2]=17;
//p-&number[LENTH-3]=17;
//-----------------------------------------------------------------------------------------------
void filesite()
//文件重写
FILE *fp=fopen(path,"at");
while(p-&next && p-&next!=head)
if(0==i) fprintf(fp,"%-4s
%-12s\n","序号","姓名","电话号码");
fprintf(fp,"%-8s
%-12s \n",p-&count,p-&name,p-&number);
printf("file
memory error! please check\n");
//===============================导航界面的两个函数============================
void face(char a[][80])
int i=8,BC=8;
//BC为control实参
while(x=getch())
if(x=='\r')
while(a[BC][5]!=16)
controlmain(BC);
if(x=='w' || x=='a' )
if(a[8][5]==16 )
a[i][5]=' ';
a[i][6]=' ';
a[i][59]=' ';
a[i][58]=' ';
a[i][5]=16;
a[i][6]=16;
a[i][59]=17;
a[i][58]=17;
system("cls");
while(j&20)
printf("%s\n",a+j++);
else if(x=='s' || x=='d')
if(a[14][5]==16)
a[i][5]=' ';
a[i][6]=' ';
a[i][59]=' ';
a[i][58]=' ';
a[i][5]=16;
a[i][6]=16;
a[i][59]=17;
a[i][58]=17;
system("cls");
while(j&20)
printf("%s\n",a+j++);
//---------------------------------------------------------------------------
char a[20][80]={"\0",
^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^",
请选择要进行的操作:
&----------&
&----------&
&----------&
&----------&
a[8][5]=16;
a[8][6]=16;
a[8][59]=17;
a[8][58]=17;
while(i&20)
printf("%s\n",a+i++);
//=====================================================================
void facenode()
//节点操作表
char x='z';
while(x=getch() )
if(x=='\r')
while(p-&count[1]!=16)
if(p==head) { controlmain(99);}
//返回主菜单
opration(AC);
//AC为要修改或删除的节点序号 int型
if(x=='w' || x=='a')
if(head-&next-&count[1]==16 )
p-&count[1]=' ';
p-&count[2]=' ';
//p-&number[LENTH-2]=' ';
//p-&number[LENTH-3]=' ';
p-&count[1]=16;
p-&count[2]=16;
//p-&number[LENTH-2]=17;
//p-&number[LENTH-3]=17;
system("cls");
else if(x=='s' || x=='d')
if(head-&count[1]==16 )
p-&count[1]=' ';
p-&count[2]=' ';
//p-&number[LENTH-2]=' ';
//p-&number[LENTH-3]=' ';
p-&count[1]=16;
p-&count[2]=16;
//p-&number[LENTH-2]=17;
//p-&number[LENTH-3]=17;
system("cls");
//-------------------------------------------------------------------------
node *newone()
//创建头节点
p=(node *)malloc(sizeof(node));
memset(p-&count,' ',LENTH);
p-&next=NULL;
p-&prior=NULL;
//--------------------------------------------------------------------------
void start()
//链表初始化
head=newone();
strcpy(head-&name,"返回主菜单");
memset(head-&count,' ',5);
memset(&head-&count[5],'\0',5);
memset(head-&number,'\0',LENTH);
head-&prior=
//----------------------------------------------------------------------
void creat()
//添加新用户
int i=0,j=0;char x,c;
char arry[10][40]={"\0",
要继续新建联系人?
FILE *fp=fopen(path,"at");
temp=newone();
//P指向最后一个节点
i=atoi(head-&prior-&count);
//求出最后一个节点的序号,即总数
arry[3][3]=16;
arry[3][4]=16;
arry[3][22]=17;
arry[3][23]=17;
system("cls");
printf("\n\n\n\n\n\n\n\n");
while(j&10)
%s\n",arry+j++);
while(x=getch())
system("cls");
printf("\n\n\n\n\n\n\n\n");
while(j&10)
%s\n",arry+j++);
if(x=='\r')
if(arry[3][3]==16)
system("cls");
memset(temp-&name,'\0',LENTH);
memset(temp-&number,'\0',LENTH);
printf("\n\n
请输入姓名和电话:\n");
scanf("%s%s",&temp-&name,&temp-&number);
printf("\n\n_________________确定将%s的信息存入通讯录?Y/N________________\n",temp-&name);
c=getch();
if(c=='y' || c=='Y')
fp=fopen(path,"at");
q=newone();
//序号寸入
sprintf(&q-&count[5],"%d",i);
sprintf(&head-&count[5],"%d",i);
//导入姓名与电话
strcpy(q-&name,temp-&name);
strcpy(q-&number,temp-&number);
//接入链表
p-&next=q;
q-&prior=p;
head-&prior=q;
fprintf(fp,"%-4s
%-12s\n","序号","姓名","电话号码");
fprintf(fp,"%-8s
%-12s \n",q-&count,q-&name,q-&number);
printf("\n\n\n___________________________
已成功导入%s\n",path);
fclose(fp);
Sleep(1000);
else printf("通讯录文件出错!请检查PATH\n");
p-&count[1]=16;p-&count[2]=16;
p-&number[LENTH-2]=17;p-&number[LENTH-3]=17;
if(arry[5][3]==16)
system("cls");
picture();
if(x=='w' || x=='a')
if(arry[3][3]==16)
arry[3][3]=16;
arry[3][4]=16;
arry[3][22]=17;
arry[3][23]=17;
arry[5][3]=' ';
arry[5][4]=' ';
arry[5][22]=' ';
arry[5][23]=' ';
system("cls");
printf("\n\n\n\n\n\n\n\n");
while(j&10)
%s\n",arry+j++);
else if(x=='s' || x=='d')
if(arry[5][3]==16)
arry[3][3]=' ';
arry[3][4]=' ';
arry[3][22]=' ';
arry[3][23]=' ';
arry[5][3]=16;
arry[5][4]=16;
arry[5][22]=17;
arry[5][23]=17;
system("cls");
printf("\n\n\n\n\n\n\n\n");
while(j&10)
%s\n",arry+j++);
//---------------------------------------------------------------------------
void del(int n)
//删除用户,n为要删除的节点序号int
node *q=head,*p=
while(p!=head-&prior)
if(atoi(&p-&count[5])==n)
//sprintf(head-&count+5,"%d",i);
//当删除的为最后一个节点时yy
if(p-&next==head)
system("title 111");
head-&prior=q;
printf("删除完成!");
filesite();
//文件重写
Sleep(500);
system("cls");
//常规删除
q-&next=p-&
p-&next-&prior=p-&
//序号进一
j=atoi(q-&count);
sprintf(&q-&count[5],"%d",j);
}while(q-&next!=head);
filesite();
//文件重写
printf("删除完成!\n");
Sleep(400);
system("cls");
} // while
//-----------------------------------------------------------------------------
void search()
//动态搜索
char test[LENTH]={"\0"};
//定义测试关键码及长度
char arr[LENTH]={"\0"};
char arrname[LENTH]={"\0"};
char num[10]={"序号"},name[10]={"姓名"},tel[10]={"电话"};
system("cls");
printf("\n\n==================================查找===============================\n\n");
while(i&LENTH)
system("cls");
printf("\n\n\n
%-12s\n",num,name,tel);
while(p-&next && p-&next!=head)
memset(arr,'\0',LENTH);
memset(arrname,'\0',LENTH);
strncpy(arr,p-&number,i);
strncpy(arrname,p-&name,i);
if(0==strcmp(arr,test)
0==strcmp(arrname,test))
printf("_______________________________________________________________\n");
%12s\n",&p-&count[3],p-&name);
\n",p-&number);
printf("\n\n=========================查找=============================\n\n");
puts(test);
putchar(10);
temp=getch();
if(!i && temp=='\b')
if(i && temp=='\b')
test[i-1]='\0';
else if(!i && temp=='\b')
}//while输入
printf("查找结束\n");
Sleep(500);
system("cls");
//------------------------------------------------------------------------------
void list()
//显示全部列表
char num[10]={"序号"},name[10]={"姓名"},tel[10]={"电话"};
putchar(10);putchar(10);
if(!p-&next)
printf("\n\n\n_______________ 通讯录目前为空!
是否开始新建? Y/N _________________\n\n");
x=getch();
if(x=='Y' || x=='y')
system("cls");
system("cls");
picture();
%-12s\n\n",num,name,tel);
printf("_______________________________________________________________\n");
%12s\n",p-&count,p-&name);
\n",p-&number);
}while(p-&next && p-&next!=head-&next);
printf("_______________________________________________________________\n");
printf("\n
个人信息!\n\n",&head-&prior-&count[3]);
//-------------------------------总控制台------------------------------------------
void control(int x,int p)
//X为操作类型,P为操作码(int)
char temp[LENTH]={'\0'};
//char pchar[LENTH]={'\0'};
//sprintf(pchar,"%s",p);
if(p!=atoi(pchar))
printf("need debug!!!
please check!\n ");
Sleep(100000);
while(atoi(&q-&count[5])!=p)
//目标节点定位
//修改用户姓名
printf("请输入新的用户名:\n");
scanf("%s",temp);
printf("\n确定修改名为%s的用户信息? Y/N\n",q-&name);
c=getch();
if(c=='Y' || c=='y')
memset(q-&name,'\0',LENTH);
strcpy(q-&name,temp);
filesite();
//文件重写
printf("修改成功!\n");
Sleep(500);
system("cls");
facenode();
printf("放弃存入!\n");
Sleep(500);
system("cls");
facenode();
//修改用户电话号码
printf("请输入新的电话号码:\n");
scanf("%s",temp);
printf("\n确定修改名为%s的用户信息? Y/N\n",q-&name);
c=getch();
if(c=='Y' || c=='y')
memset(q-&number,'\0',LENTH);
strcpy(q-&number,temp);
filesite();
//文件重写
printf("修改成功!\n");
Sleep(500);
system("cls");
facenode();
printf("放弃存入!\n");
Sleep(500);
system("cls");
facenode();
case 25:del(p);check();list();facenode();
//----------------------------以上为单个用户的修改删除----------------------------------------------
//返回当前列表
system("cls");
facenode();
default: printf("error!\n");
//-----------------------------------------------------------------------
void controlmain(int x)
//主菜单对应的功能
check();list();system("cls");check();list();facenode();
case 10: creat();system("cls");picture();
case 12: search();picture();
case 14: exit(0);
case 99: system("cls");picture();
default: printf("\n\n");
}//-------------------------以上为主导航界面需要--20以内-------------------------------------
//-----------------------------------------------------------------------
void opration(int p)
//单个用户对应的操作
由facenode()调用
char arr[8][60]={"\0",
修改该用户姓名
修改该用户电话
删除该用户资料
printf("\n\n______________________________________________________\n");
arr[1][1]=16;
arr[1][2]=16;
arr[1][19]=17;
arr[1][20]=17;
system("cls");
printf("\n\n\n\n\n\n\n\n
您想做什么?\n\n");
while(i&8)
%s\n",arr[i++]);
faceopration(arr,p);
//p为要修改或删除节点序号,int类型,由facenode()中调用opration()函数传入
void faceopration(char a[][60],int p)
//节点操作表
char x='z';
int i=1,CC=1;
while(x=getch())
if(x=='\r')
while(a[CC][1]!=16)
control(CC+20,p);
//CC为操作码,P为要修改删除的节点序号int型由AC计数传入
if(x=='w' || x=='a' )
if(a[1][1]==16 )
a[i][1]=' ';
a[i][2]=' ';
a[i][19]=' ';
a[i][20]=' ';
a[i][1]=16;
a[i][2]=16;
a[i][19]=17;
a[i][20]=17;
system("cls");
printf("\n\n\n\n\n\n\n\n
您想做什么?\n\n");
while(j&8)
%s\n",a+j++);
else if(x=='s' || x=='d')
if(a[7][1]==16)
a[i][1]=' ';
a[i][2]=' ';
a[i][19]=' ';
a[i][20]=' ';
a[i][1]=16;
a[i][2]=16;
a[i][19]=17;
a[i][20]=17;
system("cls");
printf("\n\n\n\n\n\n\n\n
您想做什么?\n\n");
while(j&8)
%s\n",a+j++);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////
system("title 通讯录
--by Giant");
picture();
///////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & &C语言(clang.cc)研究中心
1.C语言网遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.C语言网的原创文章,请转载时务必注明文章作者和来源3.作者投稿可能会经C语言网编辑修改或补充。
关注C语言微信,随时掌握C语言技术c语言程序设计 实现一个链表的插入,删除,输出 结果这个代码输出时老是出错,求帮忙_百度知道
c语言程序设计 实现一个链表的插入,删除,输出 结果这个代码输出时老是出错,求帮忙
#include&stdio.h&#include&stdlib.h&typedef struct listnode{
struct listnode 订胆斥感俪啡筹拾船浆*}linknode,*linklist creatlist(int length)
//建立链表(头插法)//{int i=1;listnode *p;head=NULL;printf(&请输入链表中的元素:&);scanf(&%d&,&number);while(i&length){p=(listnode *)malloc (sizeof(listnode));p-&data=p-&next=head=p;scanf(&%d&,&number);i=i+1;}}linklist insertlist(linklist head,int i)
//插入//{int j,n;listnode *q,*p;printf(&请输入插入的数值:\n&);scanf(&%d&,&n);p=for(j=1;p!=NULL && j&i;j++)
p=p-&q=(linklist)malloc (sizeof (linknode));q-&data=n;q-&next=p-&p-&next=q;}linklist deletelist(linklist head,int i)
//删除{listnode *p,*q;p=for(j=1;p!=NULL && j&i;j++)
p=p-&q=p-&p=q-&free(q);}void output(linklist head)
//输出{ p=head-& while(p!=NULL) {
printf(&%d,&,p-&data);
p=p-& }}void main()
//主函数{linklist L,int l,a,b;printf(&请输入链表中元素的个数\n&);scanf(&%d&,&l);head=creatlist(l); printf(&输入要插入元素的位置:\n&);scanf(&%d&,&a);if(a&1||a&l+1)
printf(&error&);else{ insertlist(head,a);
printf(&插入后的新链表是:\n&);
output(head);}printf(&输入要删除元素的位置:\n&);scanf(&%d&,&b);if(b&1||a&l)
printf(&error&);else{ printf(&删除后的新链表是:\n&);
deletelist(head,b);
output(head);}}
提问者采纳
按照阁下的代码,我又写了一遍直接就可以用#include&stdio.h&#include&stdlib.h&typedef struct listnode{
struct listnode *}linknode,*/*************** * 建立链表订胆斥感俪啡筹拾船浆 ***************/linklist creatlist(int length){ linklist head = (listnode *) malloc(sizeof(listnode)); listnode *p =
printf(&请输入链表中的元素:\n&);
for(int i = 0; i & i++) {
scanf(&%d&,&number);
p-&next = (listnode *) malloc(sizeof(listnode));
p = p-& }}/*************** * 插入 ***************/linklist insertlist(linklist head, int pos){ listnode *q = (linklist) malloc(sizeof(linknode)); listnode *p =
printf(&\n请输入插入的数值:\t&); scanf(&%d&,&n);
for(int i = 0; i & pos-1; i++)
q-&data = q-&next = p-& p-&next = }/*************** * 删除 ***************/linklist deletelist(linklist head, int pos){ listnode *p = head,*q;
for(int i = 0; i & pos-2; i++)
q = p-& p-&next = q-&
free(q); }/*************** * 输出 ***************/void output(linklist head){ linklist p =
while(p!=NULL) {
printf(&%d &,p-&data);
p = p-& }}/*************** * 主函数 ***************/int main(){ int l,a,b;
printf(&请输入链表中元素的个数:\t&); scanf(&%d&,&l);
head=creatlist(l);
printf(&\n输入要插入元素的位置:\t&); scanf(&%d&,&a);
if(a & 1 || a & l)
printf(&error&); else {
insertlist(head, a);
printf(&\n插入后的新链表是:\t&);
output(head); }
printf(&\n输入要删除元素的位置:\t&); scanf(&%d&,&b);
if(b & 1 || a & l)
printf(&error&); else {
printf(&\n删除后的新链表是:\t&);
deletelist(head,b);
output(head); } return 0;}
提问者评价
其他类似问题
为您推荐:
其他4条回答
更正错误,下面是调试好的代码
#include&stdio.h&
#include&stdlib.h&
typedef struct listnode{
struct listnode *
}linknode,*
linklist creatlist(int length)
//建立链表(头插法)//
listnode *p;
head=NULL;
printf(&请输入链表中的元素:&);
//scanf(&%d&,&number);
while(i&=length)
scanf(&%d&,&number);
p=(listnode *)malloc (sizeof(listnode));
//scanf(&%d&,&number);
linklist insertlist(linklist head,int i)
#include&stdio.h&
下面是调试通过的代码,你上面写的定义都写的乱七八糟,二楼的居然也没改就帖上去了!
不过我这个不能删除最后一个节点,这个问题留给你息解决吧
#include&stdlib.h&
typedef struct listnode{
struct listnode *
}linknode,*
linklist creatlist(int length)
linknode *p;
head=NULL;
while(i&=length)
printf(&请输入链表中的元素:&);
scanf(&%d&,&number);
p=(linknode *)malloc (sizeof(linknode));
linklist insertlist(linklist head,in...
#include&stdio.h&
#include&stdlib.h&
struct listnode{
struct listnode *
struct listnode *creatlist(int length)
//建立链表(头插法)
//linklist *
//listnode *p;
linknode-&next=NULL;
linknode=&
printf(&请输入链表中的元素:&);
scanf(&%d&,&number);
while(i&length)
linknode-&next=(struct listnode *)malloc (sizeof(struct listnode));
linknode=linknode-&
linknode-&data=
linknode-&next=NULL;
//p-&next=
scanf(&%d&,&number);
楼上建立链表点问题,应该将建立链表改掉:/*************** * 建立链表 ***************/linklist creatlist(int length){ linklist head = (listnode *) malloc(sizeof(listnode)); listnode *p = listnode *q;
printf(&请输入链表中的元素:\n&);
for(int i = 0; i & i++) {
scanf(&%d&,&number);
q = (listnode *) malloc(sizeof(listnode));
q-&next = NULL;
c语言程序设计的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁求解C语言中建立一个对链表按照学号进行排序的问题
求解C语言中建立一个对链表按照学号进行排序的问题
结构体,链表的建造及输出函数如下,求一个对链表按学号升序排列的函数。
#define NULL 0
#define LEN sizeof(struct student)
struct student
char name[20];
struct student *
struct student *creat(void)/*建造*/
struct student*
struct student *p1,*p2;
p1=p2=(struct student *)malloc(LEN);
scanf(&%ld,%s&,&p1-&num,p1-&name);
head=NULL;
while(p1-&num!=0)
if(n==1)head=p1;
else p2-&next=p1;
p1=(struct student*)malloc(LEN);
scanf(&%ld,%s&,&p1-&num,p1-&name);
p2-&next=NULL;
return(head);
void print(struct student *head)/*输出*/
struct student *p;
printf(&\nNOW.These%d records are:\n&,n);
if(head!=NULL)
printf(&%ld,%s\n&,p-&num,p-&name);
while(p!=NULL);
==========================
功能:选择排序(由小到大)
返回:指向链表表头的指针
==========================
选择排序的基本思想就是反复从还未排好序的那些节点中,
选出键值(就是用它排序的字段,我们取学号num为键值)最小的节点,
依次重新组合成一个链表。
我认为写链表这类程序,关键是理解:
head存储的是第一个节点的地址,head-&next存储的是第二个节点的地址;
任意一个节点p的地址,只能通过它前一个节点的next来求得。
单向链表的选择排序图示:
----&[1]----&[3]----&[2]...----&[n]----&[NULL](原链表)
head 1-&next 3-&next 2-&next n-&next
----&[NULL](空链表)
----&[1]----&[2]----&[3]...----&[n]----&[NULL](排序后链表)
first 1-&next 2-&next 3-&next tail-&next
图10:有N个节点的链表选择排序
1、先在原链表中找最小的,找到一个后就把它放到另一个空的链表中;
2、空链表中安放第一个进来的节点,产生一个有序链表,并且让它在原链表中分离出来(此时要注意原链表中出来的是第一个节点还是中间其它节点);
3、继续在原链表中找下一个最小的,找到后把它放入有序链表的尾指针的next,然后它变成其尾指针;
struct student *SelectSort(struct student *head)
struct student * /*排列后有序链的表头指针*/
struct student * /*排列后有序链的表尾指针*/
struct student *p_ /*保留键值更小的节点的前驱节点的指针*/
struct student * /*存储最小节点*/
struct student *p; /*当前比较的节点*/
first = NULL;
while (head != NULL) /*在链表中找键值最小的节点。*/
/*注意:这里for语句就是体现选择排序思想的地方*/
for (p=head,min= p-&next!=NULL; p=p-&next) /*循环遍历链表中的节点,找出此时最小的节点。*/
if (p-&next-&num & min-&num) /*找到一个比当前min小的节点。*/
p_min = /*保存找到节点的前驱节点:显然p-&next的前驱节点是p。*/
min = p-& /*保存键值更小的节点。*/
/*上面for语句结束后,就要做两件事;一是把它放入有序链表中;二是根据相应的条件判断,安排它离开原来的链表。*/
/*第一件事*/
if (first == NULL) /*如果有序链表目前还是一个空链表*/
first = /*第一次找到键值最小的节点。*/
tail = /*注意:尾指针让它指向最后的一个节点。*/
else /*有序链表中已经有节点*/
tail-&next = /*把刚找到的最小节点放到最后,即让尾指针的next指向它。*/
tail = /*尾指针也要指向它。*/
/*第二件事*/
if (min == head) /*如果找到的最小节点就是第一个节点*/
head = head-& /*显然让head指向原head-&next,即第二个节点,就OK*/
else /*如果不是第一个节点*/
p_min-&next = min-& /*前次最小节点的next指向当前min的next,这样就让min离开了原链表。*/
if (first != NULL) /*循环结束得到有序链表first*/
tail-&next = NULL; /*单向链表的最后一个节点的next应该指向NULL*/
==========================
功能:直接插入排序(由小到大)
返回:指向链表表头的指针
==========================
直接插入排序的基本思想就是假设链表的前面n-1个节点是已经按键值
(就是用它排序的字段,我们取学号num为键值)排好序的,对于节点n在
这个序列中找插入位置,使得n插入后新序列仍然有序。按照这种思想,依次
对链表从头到尾执行一遍,就可以使无序链表变为有序链表。
单向链表的直接插入排序图示:
----&[1]----&[3]----&[2]...----&[n]----&[NULL](原链表)
head 1-&next 3-&next 2-&next n-&next
----&[1]----&[NULL](从原链表中取第1个节点作为只有一个节点的有序链表)
----&[3]----&[2]...----&[n]----&[NULL](原链表剩下用于直接插入排序的节点)
first 3-&next 2-&next n-&next
----&[1]----&[2]----&[3]...----&[n]----&[NULL](排序后链表)
head 1-&next 2-&next 3-&next n-&next
图13:有N个节点的链表直接插入排序
1、先在原链表中以第一个节点为一个有序链表,其余节点为待定节点。
2、从图12链表中取节点,到图11链表中定位插入。
3、上面图示虽说画了两条链表,其实只有一条链表。在排序中,实质只增加了一个用于指向剩下需要排序节点的头指针first罢了。
这一点请读者务必搞清楚,要不然就可能认为它和上面的选择排序法一样了。
struct student *InsertSort(struct student *head)
struct student * /*为原链表剩下用于直接插入排序的节点头指针*/
struct student *t; /*临时指针变量:插入节点*/
struct student *p; /*临时指针变量*/
struct student *q; /*临时指针变量*/
first = head-& /*原链表剩下用于直接插入排序的节点链表:可根据图12来理解。*/
head-&next = NULL; /*只含有一个节点的链表的有序链表:可根据图11来理解。*/
while (first != NULL) /*遍历剩下无序的链表*/
/*注意:这里for语句就是体现直接插入排序思想的地方*/
for (t=first, q= ((q!=NULL) && (q-&num & t-&num)); p=q, q=q-&next); /*无序节点在有序链表中找插入的位置*/
/*退出for循环,就是找到了插入的位置*/
/*注意:按道理来说,这句话可以放到下面注释了的那个位置也应该对的,但是就是不能。原因:你若理解了上面的第3条,就知道了。*/
first = first-& /*无序链表中的节点离开,以便它插入到有序链表中。*/
if (q == head) /*插在第一个节点之前*/
else /*p是q的前驱*/
t-&next = /*完成插入动作*/
/*first = first-&*/
==========================
功能:冒泡排序(由小到大)
返回:指向链表表头的指针
==========================
直接插入排序的基本思想就是对当前还未排好序的范围内的全部节点,
自上而下对相邻的两个节点依次进行比较和调整,让键值(就是用它排
序的字段,我们取学号num为键值)较大的节点往下沉,键值较小的往
上冒。即:每当两相邻的节点比较后发现它们的排序与排序要求相反时,
就将它们互换。
单向链表的冒泡排序图示:
----&[1]----&[3]----&[2]...----&[n]----&[NULL](原链表)
head 1-&next 3-&next 2-&next n-&next
----&[1]----&[2]----&[3]...----&[n]----&[NULL](排序后链表)
head 1-&next 2-&next 3-&next n-&next
图14:有N个节点的链表冒泡排序
任意两个相邻节点p、q位置互换图示:
假设p1-&next指向p,那么显然p1-&next-&next就指向q,
p1-&next-&next-&next就指向q的后继节点,我们用p2保存
p1-&next-&next指针。即:p2=p1-&next-&next,则有:
[ ]----&[p]----------&[q]----&[ ](排序前)
p1-&next p1-&next-&next p2-&next
[ ]----&[q]----------&[p]----&[ ](排序后)
1、排序后q节点指向p节点,在调整指向之前,我们要保存原p的指向节点地址,即:p2=p1-&next-&next;
2、顺着这一步一步往下推,排序后图16中p1-&next-&next要指的是p2-&next,所以p1-&next-&next=p2-&
3、在图15中p2-&next原是q发出来的指向,排序后图16中q的指向要变为指向p的,而原来p1-&next是指向p的,所以p2-&next=p1-&
4、在图15中p1-&next原是指向p的,排序后图16中p1-&next要指向q,原来p1-&next-&next(即p2)是指向q的,所以p1-&next=p2;
5、至此,我们完成了相邻两节点的顺序交换。
6、下面的程序描述改进了一点就是记录了每次最后一次节点下沉的位置,这样我们不必每次都从头到尾的扫描,只需要扫描到记录点为止。
因为后面的都已经是排好序的了。
struct student *BubbleSort(struct student *head)
struct student * /*控制循环比较*/
struct student *p; /*临时指针变量*/
struct student *p1;
struct student *p2;
p1 = (struct student *)malloc(LEN);
p1-&next = /*注意理解:我们增加一个节点,放在第一个节点的前面,主要是为了便于比较。因为第一个节点没有前驱,我们不能交换地址。*/
head = p1; /*让head指向p1节点,排序完成后,我们再把p1节点释放掉*/
for (endpt=NULL; endpt!= endpt=p) /*结合第6点理解*/
for (p=p1= p1-&next-&next!= p1=p1-&next)
if (p1-&next-&num & p1-&next-&next-&num) /*如果前面的节点键值比后面节点的键值大,则交换*/
p2 = p1-&next-& /*结合第1点理解*/
p1-&next-&next = p2-& /*结合第2点理解*/
p2-&next = p1-& /*结合第3点理解*/
p1-&next = p2; /*结合第4点理解*/
p = p1-&next-& /*结合第6点理解*/
p1 = /*把p1的信息去掉*/
head = head-& /*让head指向排序后的第一个节点*/
free(p1); /*释放p1*/
p1 = NULL; /*p1置为NULL,保证不产生“野指针”,即地址不确定的指针变量*/
==========================
功能:插入有序链表的某个节点的后面(从小到大)
返回:指向链表表头的指针
==========================
有序链表插入节点示意图:
----&[NULL](空有序链表)
图18:空有序链表(空有序链表好解决,直接让head指向它就是了。)
以下讨论不为空的有序链表。
----&[1]----&[2]----&[3]...----&[n]----&[NULL](有序链表)
head 1-&next 2-&next 3-&next n-&next
图18:有N个节点的有序链表
插入node节点的位置有两种情况:一是第一个节点前,二是其它节点前或后。
----&[node]----&[1]----&[2]----&[3]...----&[n]----&[NULL]
head node-&next 1-&next 2-&next 3-&next n-&next
图19:node节点插在第一个节点前
----&[1]----&[2]----&[3]...----&[node]...----&[n]----&[NULL]
head 1-&next 2-&next 3-&next node-&next n-&next
图20:node节点插在其它节点后
struct student *SortInsert(struct student *head, struct student *node)
struct student *p; /*p保存当前需要检查的节点的地址*/
struct student *t; /*临时指针变量*/
if (head == NULL) /*处理空的有序链表*/
node-&next = NULL;
n += 1; /*插入完毕,节点总数加1*/
p = /*有序链表不为空*/
while (p-&num & node-&num && p != NULL) /*p指向的节点的学号比插入节点的学号小,并且它不等于NULL*/
t = /*保存当前节点的前驱,以便后面判断后处理*/
p = p-& /*后移一个节点*/
if (p == head) /*刚好插入第一个节点之前*/
node-&next =
else /*插入其它节点之后*/
t-&next = /*把node节点加进去*/
node-&next =
n += 1; /*插入完毕,节点总数加1*/
测试代码如下:
/*测试SelectSort():请编译时去掉注释块*/
head = SelectSort(head);
Print(head);
/*测试InsertSort():请编译时去掉注释块*/
head = InsertSort(head);
Print(head);
/*测试BubbleSort():请编译时去掉注释块*/
head = BubbleSort(head);
Print(head);
/*测试SortInsert():上面创建链表,输入节点时请注意学号num从小到大的顺序。请编译时去掉注释块*/
stu = (struct student *)malloc(LEN);
printf(&/nPlease input insert node -- num,score: &);
scanf(&%ld,%f&,&stu-&num,&stu-&score);
head = SortInsert(head,stu);
free(stu);
stu = NULL;
Print(head);
转载:http://blog.csdn.net/northplayboy/article/details/552388
请遵守网上公德,勿发布广告信息
相关问答:
目前你的代码没有问题,你有什么问题吗?
你想干什么?
目前你的代码没有问题

我要回帖

更多关于 c语言链表详解 的文章

 

随机推荐