标题:关于链表排序~
只看楼主
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
得分:0 
为强化通用性,在强制类型转换上费了点功夫,另测试了下链表头插、中间插的插入功能,做了些许修改。先随便写了个交换数据方式的选择排序法的链表排序,并用同一个排序函数演示了“按学号顺序排序、按C语言成绩倒序排序、按平均成绩倒序排序”,演示结果正确。
链表排序函数:struct student *lsort(struct student *head,int offset,int vartype,int sortflg)
参数说明:
    表头指针       head
    排序变量偏移量 offset
    排序变量类型   vartype(0:char、1:int、2:float、3:double、4、string暂时忽略)
    排序方式       sortflg(0:增序、1:降序)

代码如下:
程序代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct student
{
    int num;
    float c;
    float vb;
    float java;
    float ave;
    struct student *next;
};
struct student *insert(struct student *head,struct student num,int pos)
{//在指定位置插入一个数据为num的节点,pos=0头插,-1尾插
    int i=0;
    struct student *p,*pre,*ph;
    p=(struct student*)malloc(sizeof(struct student));
    if (p==NULL)return p;
    *p=num;
    pre=NULL;
    ph=head;
    while(pos&&pos!=++i&&ph)
    {
        pre=ph;
        ph=ph->next ;
    }
    if(pre==NULL)
    {
        p->next=head;
        head=p;
    }
    else
    {
        pre->next=p;
        p->next=ph;
    }
    return head;
}

void listsco(struct student *head)
{//显示链表成绩
    printf("学号    C语言   VB语言  JAVA    平均分\n");
    while(head!=NULL)
    {
        printf("%-8d%-8.2f%-8.2f%-8.2f%-8.2f\n",head->num ,head->c ,head->vb ,head->java ,head->ave );
        head=head->next ;
    }
}

struct student *lsort(struct student *head,int offset,int vartype,int sortflg)
{
    /*交换数据方式链表排序参数说明:
    表头指针       head
    排序变量偏移量 offset
    排序变量类型   vartype(0:char、1:int、2:float、3:double、4、string暂时忽略)
    排序方式       sortflg(0:增序、1:降序)*/
    struct student *pi,*pj,*p,num;
    unsigned long i,j,k;
    pi=head;
    while(pi->next)
    {
        p=pi;
        pj=pi->next;
        while(pj)
        {
            i=(unsigned long)p+offset;
            j=(unsigned long)pj+offset;
            if(vartype==0)k=(int)(*(char*)i>*(char*)j)^sortflg;
            if(vartype==1)k=(int)(*(int*)i>*(int*)j)^sortflg;
            if(vartype==2)k=(int)(*(float*)i>*(float*)j)^sortflg;
            if(vartype==3)k=(int)(*(double*)i>*(double*)j)^sortflg;
            if(k)p=pj;
            pj=pj->next;
        }
        if(p!=pi)
        {
            num=*p;
            *p=*pi;
            *pi=num;
            pj=p->next;
            p->next=pi->next;
            pi->next=pj;
        }
        pi=pi->next;
    }
    return head;
}
void main()
{
    struct student *head=NULL,*p,num;
    int i;
    srand(time(0));
    for(i=0;i<8;i++)
    {
        num.num=i+1;
        num.c =(rand()%800)/10.0+20;
        num.vb =(rand()%800)/10.0+20;
        num.java  =(rand()%800)/10.0+20;
        num.ave =(num.c+num.vb+num.java)/3;
        num.next =NULL;
        head=insert(head,num,-1);
    }
    num.num=18;
    head=insert(head,num,3);  //测试中间插入节点
    num.num=38;
    head=insert(head,num,0);  //测试头插
    listsco(head);
    head=lsort(head,(int)(&head->num)-(int)head,1,0);
    printf("按学号顺序排序\n");
    listsco(head);
    head=lsort(head,(int)(&head->c)-(int)head,2,1);
    printf("按C语言成绩倒序排序\n");
    listsco(head);
    head=lsort(head,(int)(&head->ave)-(int)head,2,1);
    printf("按平均成绩倒序排序\n");
    listsco(head);
    while(head)
    {//释放申请的空间要成为习惯
        p=head;
        head=head->next;
        free(p);
    }
    system("pause");
}
2017-02-12 08:13
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
得分:0 
回复 11楼 xzlxzlxzl
x版主程序通用性较强~赞一个~九九觉得如果比较函数用函数指针处理,在调用排序函数主体的时候把函数指针作为参数传进去处理就更加清晰了~如果再把yang的排序方法结合在一起就会更清晰易懂了~

还有x版主调用不确定结构体成员的方法值得借鉴~想不到之前九九写的大型学生信息管理系统比较的引用方法差不多~x版主也是这样写更加肯定了九九那种写法了~

不过九九还有一个小问题想请教一下~比较部分把int float double char型统一换成double比较这样合适吗?~~

[此贴子已经被作者于2017-2-12 13:35编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-02-12 13:33
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
得分:0 
回复 12楼 九转星河
1、我也考虑过使用通用库里的sort函数那样,外部编写一个comp函数排序,但实际上这并不具备通用性,用户需要为结构体内的每一个成员变量的排序编写一个comp。而我这个排序只要用户知道使用方法,结构体名称相同(都叫student,而结构体内成员可随便定义),则可轻松地对结构体内任何成员变量按指定方式排序,既可以顺序、也可以倒序,拿去后基本适合所有类型的链表排序,不用改动就可用。
2、不能统一使用double,首先double只适用数据比较,无法进行字符串比较,其次,我的代码是使用强制指针类型转换,不同类型的变量长度不同,强制为double后会读入8个字节的数据比较,肯定得不到正确结果。
3、刚刚将交换数据的排序改成了交换节点的排序,增加了节点删除函数,数据结构里增加了姓名。原本还想增加一个通用的节点查找函数,想想也没什么新意,没做。普通链表大概也就玩成这样差不多了,有新的学习需要再做。至于什么菜单、文件这些,用c写实在没必要,在面向对象编程里这些都不是事。修改后的代码运行效果如下(代码下一楼提供):
****************************************************************************************************************
请按任意键继续. . .
学号    姓名    C语言   VB语言  JAVA    平均分
38      Elrtb   46.90   78.60   93.20   72.90   
1       Gxryec  78.40   55.00   89.90   74.43   
2       Ttalb   25.10   45.10   64.50   44.90   
18      Elrtb   46.90   78.60   93.20   72.90   
3       Lwfrr   52.90   58.10   98.80   69.93   
4       Pislzk  27.70   28.50   71.70   42.63   
5       Ooahi   25.00   96.80   87.40   69.73   
6       Kdhjx   40.70   87.10   50.70   59.50   
7       Aztzyi  93.50   83.90   56.20   77.87   
8       Elrtb   46.90   78.60   93.20   72.90   
按学号顺序排序
学号    姓名    C语言   VB语言  JAVA    平均分
1       Gxryec  78.40   55.00   89.90   74.43   
2       Ttalb   25.10   45.10   64.50   44.90   
3       Lwfrr   52.90   58.10   98.80   69.93   
4       Pislzk  27.70   28.50   71.70   42.63   
5       Ooahi   25.00   96.80   87.40   69.73   
6       Kdhjx   40.70   87.10   50.70   59.50   
7       Aztzyi  93.50   83.90   56.20   77.87   
8       Elrtb   46.90   78.60   93.20   72.90   
18      Elrtb   46.90   78.60   93.20   72.90   
38      Elrtb   46.90   78.60   93.20   72.90   
按C语言成绩倒序排序
学号    姓名    C语言   VB语言  JAVA    平均分
7       Aztzyi  93.50   83.90   56.20   77.87   
1       Gxryec  78.40   55.00   89.90   74.43   
3       Lwfrr   52.90   58.10   98.80   69.93   
38      Elrtb   46.90   78.60   93.20   72.90   
18      Elrtb   46.90   78.60   93.20   72.90   
8       Elrtb   46.90   78.60   93.20   72.90   
6       Kdhjx   40.70   87.10   50.70   59.50   
4       Pislzk  27.70   28.50   71.70   42.63   
2       Ttalb   25.10   45.10   64.50   44.90   
5       Ooahi   25.00   96.80   87.40   69.73   
按平均成绩倒序排序
学号    姓名    C语言   VB语言  JAVA    平均分
7       Aztzyi  93.50   83.90   56.20   77.87   
1       Gxryec  78.40   55.00   89.90   74.43   
8       Elrtb   46.90   78.60   93.20   72.90   
18      Elrtb   46.90   78.60   93.20   72.90   
38      Elrtb   46.90   78.60   93.20   72.90   
3       Lwfrr   52.90   58.10   98.80   69.93   
5       Ooahi   25.00   96.80   87.40   69.73   
6       Kdhjx   40.70   87.10   50.70   59.50   
2       Ttalb   25.10   45.10   64.50   44.90   
4       Pislzk  27.70   28.50   71.70   42.63   
按姓名顺序排序
学号    姓名    C语言   VB语言  JAVA    平均分
7       Aztzyi  93.50   83.90   56.20   77.87   
8       Elrtb   46.90   78.60   93.20   72.90   
18      Elrtb   46.90   78.60   93.20   72.90   
38      Elrtb   46.90   78.60   93.20   72.90   
1       Gxryec  78.40   55.00   89.90   74.43   
6       Kdhjx   40.70   87.10   50.70   59.50   
3       Lwfrr   52.90   58.10   98.80   69.93   
5       Ooahi   25.00   96.80   87.40   69.73   
4       Pislzk  27.70   28.50   71.70   42.63   
2       Ttalb   25.10   45.10   64.50   44.90   
删除学号为38的学生记录
学号    姓名    C语言   VB语言  JAVA    平均分
7       Aztzyi  93.50   83.90   56.20   77.87   
8       Elrtb   46.90   78.60   93.20   72.90   
18      Elrtb   46.90   78.60   93.20   72.90   
1       Gxryec  78.40   55.00   89.90   74.43   
6       Kdhjx   40.70   87.10   50.70   59.50   
3       Lwfrr   52.90   58.10   98.80   69.93   
5       Ooahi   25.00   96.80   87.40   69.73   
4       Pislzk  27.70   28.50   71.70   42.63   
2       Ttalb   25.10   45.10   64.50   44.90   
2017-02-12 16:43
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
得分:0 
新增节点删除函数、排序改成节点交换排序、增加字符串排序功能:
程序代码:
#include "StdAfx.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct student
{
    int num;
    char name[20];
    float c;
    float vb;
    float java;
    float ave;
    struct student *next;
};
struct student *insert(struct student *head,struct student num,int pos)
{//在指定位置插入一个数据为num的节点,pos=0头插,-1尾插
    int i=0;
    struct student *p,*pre,*ph;
    p=(struct student*)malloc(sizeof(struct student));
    if (p==NULL)return p;
    *p=num;
    pre=NULL;
    ph=head;
    while(pos&&pos!=++i&&ph)
    {
        pre=ph;
        ph=ph->next ;
    }
    if(pre==NULL)
    {
        p->next=head;
        head=p;
    }
    else
    {
        pre->next=p;
        p->next=ph;
    }
    return head;
}

void listsco(struct student *head)
{//显示链表成绩
    printf("学号    姓名    C语言   VB语言  JAVA    平均分\n");
    while(head!=NULL)
    {
        printf("%-8d%-8s%-8.2f%-8.2f%-8.2f%-8.2f\n",head->num ,head->name,head->c ,head->vb ,head->java ,head->ave );
        head=head->next ;
    }
}

struct student *ldel(struct student *head,int pos)
{//删除指定位置节点
    struct student *p,*pre;
    int i=0;
    if(pos<1)return head;
    pre=NULL;
    p=head;
    while(p&&i++!=pos)
    {
        pre=p;
        p=p->next;
    }
    if(p)
    {
        if(pre)pre->next=p->next;
        else head=p;
        free(p);
    }
    return head;
}

struct student *lsort(struct student *head,int offset,int vartype,int sortflg)
{
    /*移动节点方式链表排序参数说明:
    表头指针       head
    排序变量偏移量 offset
    排序变量类型   vartype(0:char、1:int、2:float、3:double、4、string)
    排序方式       sortflg(0:增序、1:降序)*/
    struct student *pi,*pj,*p,*prei,*prej,*ppj;
    unsigned long i,j,k;
    char *psi,*psj;
    for(prei=NULL,pi=head;pi->next;prei=pi,pi=pi->next)
    {
        for(p=prej=ppj=pi,pj=pi->next;pj;prej=pj,pj=pj->next)
        {
            i=(unsigned long)p+offset;
            j=(unsigned long)pj+offset;
            k=0;
            if(vartype==0)k=(int)(*(char*)i>*(char*)j)^sortflg;
            if(vartype==1)k=(int)(*(int*)i>*(int*)j)^sortflg;
            if(vartype==2)k=(int)(*(float*)i>*(float*)j)^sortflg;
            if(vartype==3)k=(int)(*(double*)i>*(double*)j)^sortflg;
            if(vartype==4)
            {
                for(psi=(char*)i,psj=(char*)j;*psi&&*psj&&*psi==*psj;psi++,psj++);
                if(*psi-*psj>0)k=1^sortflg;
            }
            if(k)
            {
                ppj=prej;
                p=pj;
            }
        }
        if(p!=pi)
        {                           //找到最大或最小的元素节点p,需要将p移到pi前面
            ppj->next=p->next;      //首先将p从链表中跳开,让p前节点直接指向p后节点
            p->next=pi;             //p指向pi,已经移到当前节点前面,但此时只在链表旁路,不在整个链表中
            if(prei)prei->next=p;   //如果当前节点前一个节点有指向,则修改为指向p,p即加入链表
            else head=p;            //如果当前节点前一个节点无指向,则p就是链表头节点,p同样加入链表
            pi=p;                   //将当前节点修改为刚刚移动的节点,让循环继续
        }
    }
    return head;
}
void main()
{
    struct student *head=NULL,*p,num;
    int i,j,k;
    srand(time(0));
    for(i=0;i<8;i++)
    {
        num.num=i+1;
        k=rand()%4+3;
        for(j=0;j<k;j++)num.name[j]=rand()%26+'a';
        num.name[0]-=32;
        num.name[j]=0;
        num.c =(rand()%800)/10.0+20;
        num.vb =(rand()%800)/10.0+20;
        num.java  =(rand()%800)/10.0+20;
        num.ave =(num.c+num.vb+num.java)/3;
        num.next =NULL;
        head=insert(head,num,-1);
    }
    num.num=18;
    head=insert(head,num,3);  //测试中间插入节点
    num.num=38;
    head=insert(head,num,1);  //测试头插,0和1均可实现头插
    listsco(head);
    head=lsort(head,(int)(&head->num)-(int)head,1,0);
    printf("按学号顺序排序\n");
    listsco(head);
    head=lsort(head,(int)(&head->c)-(int)head,2,1);
    printf("按C语言成绩倒序排序\n");
    listsco(head);
    head=lsort(head,(int)(&head->ave)-(int)head,2,1);
    printf("按平均成绩倒序排序\n");
    listsco(head);
    head=lsort(head,(int)(head->name)-(int)head,4,0);
    printf("按姓名顺序排序\n");
    listsco(head);
    for(i=0,p=head;p&&p->num!=38;i++,p=p->next);
    head=ldel(head,i);
    printf("删除学号为38的学生记录\n");
    listsco(head);
    while(head)
    {//释放申请的空间要成为习惯
        p=head;
        head=head->next;
        free(p);
    }
    system("pause");
}


以上!不再更!
2017-02-12 16:46



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-474128-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.435964 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved