数据结构编程笔记三:第二章 线性表 顺序表的实现

这次主要是介绍线性顺序表的实现代码。

程序在码云上可以下载。
地址:https://git.oschina.net/601345138/DataStructureCLanguage.git

废话不多说了,看看线性表的ADT定义,了解线性表主要包括什么操作:

ADT List{
    数据对象:D={ ai | ai ∈ElemSet, i=1,2,...,n,  n≥0 } 
    数据关系:R1={ 1 ,ai >|ai-1 ,ai∈D,  i=2,...,n }
    基本操作:
             (1)线性表的初始化操作 
                  InitList(&L,n)
                  操作结果:将L初始化为空表,申请空间的大小为n。
             (2)线性表元素输入操作 
                  ListInput(&L)
                  初始条件:线性表L已存在 。
                  操作结果:线性表中的部分元素或全部元素已被赋值。     
             (3)线性表的置空操作 
                  ClearList(&L) 
                  初始条件:线性表L已存在且不为空 。
                  操作结果:将表L置为空表。
             (4)线性表的判空操作 
                  ListIsEmpty(&L)
                  初始条件:线性表L已存在。
                  操作结果:如果L为空表则返回1,否则返回0。
             (5)获取线性表元素个数的操作 
                  ListLength(L)
                  初始条件:线性表L已存在。
                  操作结果:如果L为空表则返回0,否则返回表中的元素个数。
             (6)获取线性表第i个元素的操作(用元素的位序查找元素的值) 
                  GetItem(L,i,&e)
                  初始条件:表L已存在且不为空,1<=i<=ListLength(L)。
                  操作结果:用e返回L中第i个元素的值。
             (7)确定线性表元素位置的操作 (用元素的值确定元素位置) 
                  LocateElem(L,e) 
                  初始条件:表L已存在且不为空,e为合法元素值。
                  操作结果:如果L中存在元素e,则将“当前指针”指向第一个这样的元素e所在位置并返回真,否则返回假。
             (8)线性表插入元素操作 
                  ListInsert(&L,i,e)
                  初始条件:表L已存在且不为空,e为合法元素值且1≤i≤ListLength(L)+1。
                  操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。
             (9)输出线性表元素操作 
                  PrintList(&L) 
                  初始条件:线性表L已存在且不为空。
                  操作结果:线性表L中的所有元素已输出。 
             (10)销毁线性表操作 
                  DestroyList(&L) 
                  初始条件:线性表L已存在。
                  操作结果:将L销毁。                      
}ADT List

接下来看看代码实现:

//*******************************************引入头文件*********************************************
#include 
#include   //使用了malloc、realloc、free函数 

//******************************************自定义符号常量******************************************* 

#define LIST_INIT_SIZE 100  //线性表存储空间的初始分配量
#define LISTINCREMENT 10    //线性表存储空间的分配增量 
#define OVERFLOW -2         //内存溢出错误常量
#define ILLEGAL -1          //非法操作错误常量 
#define OK 1                //表示操作正确的常量 
#define ERROR 0             //表示操作错误的常量

//******************************************自定义数据类型********************************************

typedef int Status;
typedef float ElemType;
typedef struct{
    ElemType *elem;   //线性表存储空间初始分配量
    int length;       //当前长度 
    int listsize;     //当前分配的存储容量(以sizeof(ElemType)为单位) 
}SqList;

//******************************************线性表的主要操作****************************************** 

//1.--------------------线性表的初始化操作---------------------------- 

/*
    函数:InitList_Sq
    参数:SqList &L 线性表引用 
          int n 线性表最多能存储n个元素 
    返回值:状态码,OK表示操作成功 
    作用:构造一个空线性表L  
*/
Status InitList_Sq(SqList &L, int n) { 

    //申请线性表的内存空间,申请n个元素大小的内存空间 
    L.elem = (ElemType *)malloc(n * sizeof(ElemType));  

    //判断内存是否分配成功 
    if(!L.elem){ //if(!L.elem) <=> if(L.elem == NULL) 
        printf("内存申请失败!\n");
        exit(OVERFLOW); //若内存分配失败,则退出程序
    }//if
    printf("内存申请成功!\n"); 

    //设置线性表的各个参数 
    L.length = 0;    //设置线性表的长度为0 
    L.listsize = n;  //设置线性表的空间大小为100个元素所占空间的大小

    printf("线性表创建成功!\n");
    //操作成功后返回OK 
    return OK;   
}//InitList_Sq

//2.----------------------输入线性表元素的操作-------------------

/*
    函数:ListInput_Sq
    参数:SqList &L 线性表引用 
    返回值:状态码,OK表示操作成功 
    作用:初始化线性表L中的元素 
*/
Status ListInput_Sq(SqList &L){

    //i声明在这里不是好的写法,应该将i写在for循环中,有利于缩短i的作用域,及早回收其内存空间。
    //但是由于C语言不兼容这种写法,考虑到兼容性所以将i写在外面。(C++支持这种写法) 
    int n, i;   //n代表元素的个数,i用作循环变量

    //从键盘接收元素的个数,用户输入正确后退出此循环 
    while(1){ //while(1)是一个死循环,除非在循环体内执行break语句,否则永远无法退出循环 
        //先确定元素的个数 
        printf("您想输入几个元素,请输入个数,最多不可以超过:%d\n", L.listsize);  
        scanf("%d",&n);
        if(n < 1 || n > 100) {
            //如果发生非法操作,就提醒用户重新输入
            printf("您的输入非法,请重新输入!!!\n");   
        }//if  
        else {
            break;  
        }//else    
    }//while

    //使用键盘输入的方式初始化每一个元素
    printf("请输入线性表L的元素,中间用空格隔开,最多不可以超过100个元素\n");
    for(i = 0; i < n; i++){
       scanf("%f", &L.elem[i]);                 
    }//for

    L.length = n;
    printf("该线性表初始化操作已完成!\n");
}//ListInput_Sq

//3.------------------判断线性表是否为空-------------------

/*
    函数:ListIsEmpty_Sq
    参数:SqList &L 线性表引用
    返回值:如果线性表是空表返回1,否则返回0  
    作用:判断线性表是否为空表
*/
Status ListIsEmpty_Sq(SqList &L){

    //length记录了顺序表中有效元素的个数 
    if (L.length == 0){
        printf("该线性表是空表!");
        return 1; 
    }//if 
    else { 
        return 0;
    }//else
} //ListIsEmpty_Sq

//4.-----------------------------线性表中插入元素的操作-----------------------------------

/*
    函数:ListInsert_Sq
    参数:SqList &L 线性表引用
          int i 插入位置,1 <= i <= length.Sq(L) + 1 
          ElemType e 待插入元素 
    返回值:状态码,OK表示操作成功,ERROR表示操作失败 
    作用:在顺序线性表L中第i个位置之前插入新元素e
*/
Status ListInsert_Sq(SqList &L, int i, ElemType e) {

    //pq都是工作指针,newbase是在插入的时候内存不够用才会用到的接收新分配的内存地址的指针变量 
    ElemType *p, *q, *newbase;

    //判断参数i的值是否合法 
    if(i < 1 || i > L.length + 1) { 
        return ERROR;    //i的值不合法,返回错误 
    }//if

    //插入操作之前需要先检查存储空间是否够用,若不够用就需要扩容 
    if(L.length >= L.listsize) {   //当前存储已满,需要扩容 

        //realloc函数第一个参数是已经分配了的那部分存储空间的首地址,
        //第二个参数是重新分配的内存的大小,这个参数的值一般情况下
        //会比已经分配的内存空间大一些或者小一些,但是需要注意的是
        //如果新的大小小于原内存大小,可能会导致数据丢失。

        //realloc函数的工作原理: 先判断当前的指针是否有足够的连续空间,
        //如果有,扩大mem_address指向的地址,并且将mem_address返回,
        //如果空间不够,先按照newsize指定的大小分配空间,将原有数据
        //从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域
        //(注意:原来指针是自动释放,不需要使用free),
        //同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

        //realloc函数的特点:如果我们只扩大不缩小,原先已分配内存的保存的数据不会丢失
        //这部分数据会被realloc函数转移到新的内存空间中,我们不需要
        //手工写拷贝数据的代码,也不需要手工释放第一个参数指示的已分配内存空间。
        //我们只需要接收返回值,就能得到新的内存空间的首地址 

        //使用realloc函数为线性表重新分配内存空间
        newbase = (ElemType *)realloc(L.elem, 
            (LIST_INIT_SIZE + L.listsize) * sizeof(ElemType));  

        //判断内存空间是否分配成功 
        if(!newbase){ //if(!newbase)  <=>  if(newbase == NULL)
            printf("内存申请失败!\n");
            //若内存分配失败,则后续操作就没有意义了,此时应退出程序
            exit(OVERFLOW); 
        }//if
        printf("内存申请成功!\n");
        L.elem = newbase;  //将线性表新基址赋给elem
        L.listsize += LISTINCREMENT;  //增加存储容量 
    }//if

    //找到插入位置 
    q = &(L.elem[i - 1]);  //q指示了插入位置

    //将插入位置及之后的元素后移
    for(p = &(L.elem[L.length - 1]); p >= q; --p) { 
        *(p + 1) = *p;
    }//for 

    //将e插入到q指示的插入位置 
    *q = e;

    //插入元素e后表长应该增加1  
    ++L.length;

    //操作成功 
    return OK; 
}//ListInsert_Sq 

//5.----------------------线性表中删除元素的操作----------------------------

/*
    函数:ListDelete_Sq
    参数:SqList &L 线性表引用
          int i 删除位置,1 <= i <= length.Sq(L)
          ElemType &e 带回被删除元素
    返回值:状态码,OK表示操作成功,ERROR表示操作失败 
    作用:在顺序线性表L中删除第i个元素,并返回被删除元素
*/
Status ListDelete_Sq(SqList &L, int i, ElemType &e){

    //pq是工作指针(工作指针就是起到临时保存指针变量的作用) 
    ElemType *p, *q;

    //因为无法从空表中删除一个元素,所以要判断线性表是否为空
    //if(ListIsEmpty_Sq(L)) <=> if(ListIsEmpty_Sq(L) != 0)
    if(ListIsEmpty_Sq(L)) {
        return ERROR; 
    }//if

    //判断删除位置的参数i的值是否合法 
    if(i < 1 || i > L.length) { 
        return ERROR;    //i的值不合法,返回错误
    }//if

    //找到删除位置,p指示了被删除元素的位置 
    p = &(L.elem[i - 1]);

    //保存将被删除的元素 
    e = *p;

    //找到表尾元素的位置,q指示了表尾元素的位置 
    q = L.elem + L.length - 1;

    //从被删除元素之后开始到表尾元素位置,将被删除元素之后的所有元素前移一位
    //当此循环结束时,被删除元素被其紧随其后的元素覆盖了,也就是删除了 
    for(++p; p <= q; ++p) { 
        *(p-1) = *p;
    }//for

    //删除操作执行后表长应该减1 
    --L.length;

    //操作成功 
    return OK;  
} //ListDelete_Sq

//6.-------------------线性表中查找元素的操作-------------------------------

/*说明:函数指针:函数在编译时被分配的入口地址,用函数名表示。
    函数指针指向的是程序代码存储区。
    函数指针变量定义形式:数据类型 (*指针变量名)( );   如 int (*p)();
    举个例子:(一定看清形参和实参如何传递的!) 
    #include 
    int main(){
          int max(int, int), min(int, int), add(int, int);
          void process(int, int, int (*fun)(int, int));
          int a, b;
          printf("enter a and b:");  
          scanf("%d,%d", &a, &b);
          process(a, b, max);
          process(a, b, min);
          process(a, b, add);
    }//main

    process(int x, int y, int (*fun)(int, int)){ 
          int result;
          result = (*fun)(x, y);
          printf("%d\n",result);
    }//process

    max(int x, int y) {   
          printf(“max=”);
          return(x > y ? x : y);
    }//max

    min(int x, int y){    
          printf(“min=”);
          return(x < y ? x : y);
    }//min

    add(int x, int y){   
          printf(“sum=”);  
          return(x + y);
    }
*/

/*
    函数:compare
    参数:ElemType x 待比较的第一个元素 
          ElemType y 待比较的第二个元素 
    返回值:如果元素xy的值相等,返回1,否则返回0 
    作用:比较两个元素是否相等 
*/
int compare(ElemType x, ElemType y){

    return x == y;
}//compare

/*
    函数:ListDelete_Sq
    参数:SqList &L 线性表引用
          ElemType e 查找值为e的元素 
          Status (*compare)(ElemType,ElemType) 函数指针,指向比较元素是否相同的函数 
    返回值:查找到元素在线性表中的位置,若没有找到,返回0 
    作用:在顺序线性表L中查找第一个值e满足compare()的元素在线性表中的位置 
*/
int LocateElem_Sq(SqList &L, ElemType e, Status (*compare)(ElemType,ElemType)){

    //工作指针p 
    ElemType *p;

    //查找操作首先要判断线性表是否为空,对空表执行查找操作没有意义 
    //if(ListIsEmpty_Sq(L)) <=> if(ListIsEmpty_Sq(L) != 0)
    if(ListIsEmpty_Sq(L)) { 
        return ERROR;  
    }//if

    //设置查找的起始位置 
    int i = 1;        //i的初值为第一个元素的位序
    p = L.elem;       //p的初值为第一个元素的存储位置

    //以compare函数返回值为基准在线性表中查找元素e 
    while(i <= L.length && !(*compare)(*p++, e)) { 
       ++i;
    }//while

    //如果找到了元素e的位置则返回其所在位置i 
    if(i <= L.length) {
        return i;
    }//if
    else { //如果没找到则返回0 
        return 0;
    }//else
} //LocateElem_Sq

//7. ------------------线性表中合并元素的操作----------------

/*
    函数:MergeList_Sq
    参数:SqList La 被合并的线性表a
          SqList Lb 被合并的线性表b 
          SqList &Lc 合并后得到的线性表c 
    返回值:状态码,操作成功返回OK,操作失败返回ERROR 
    作用:已知顺序线性表La和Lb的元素按值非递减排列。 
          归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列。
*/
Status MergeList_Sq(SqList La, SqList Lb, SqList &Lc) {  

     //工作指针pa, pb, pc分别保存了线性表a、b、c存储元素内存空间的首地址 
     //指针pa_last指向线性表a的表尾元素,  pb_last指向线性表b表尾元素 
     ElemType *pa, *pb, *pc, *pa_last, *pb_last;

     //合并操作要求线性表a和线性表b不能为空 
     //if(ListIsEmpty_Sq(La)) <=> if(ListIsEmpty_Sq(La) != 0)
     if(ListIsEmpty_Sq(La)) {
        return ERROR;
     }//if 

     //if(ListIsEmpty_Sq(Lb)) <=> if(ListIsEmpty_Sq(Lb) != 0)
     if(ListIsEmpty_Sq(Lb)) {
        return ERROR; 
     }//if 

     //工作指针pa, pb保存了线性表a、b存储元素内存空间的首地址 
     pa = La.elem;  
     pb = Lb.elem;

     //合并后的线性表c表长等于被合并的线性表a和b的表长之和 
     Lc.listsize = Lc.length = La.length + Lb.length;

     //确定线性表c的长度之后为其申请内存空间,大小等于a和b两表之和 
     pc = Lc.elem = (ElemType *)malloc(Lc.listsize * sizeof(ElemType));

     //检查内存分配是否成功 
     if(!Lc.elem){ //if(!Lc.elem) <=> if(Lc.elem == NULL)
        printf("内存申请失败!");
        exit(OVERFLOW); //若内存分配失败,则退出程序
     }//if

     //计算出线性表a和b的表尾元素所在位置,分别赋给对应的指针变量pa_last和pb_last 
     pa_last = La.elem + La.length - 1;
     pb_last = Lb.elem + Lb.length - 1;

     //合并pa和pb到pc

     //首先将线性表a和b中较短的一个完全合并到pc,另一个只合并一部分 
     while (pa <= pa_last && pb <= pb_last) { //循环终止条件:指示线性表a或b的工作指针有一个走到表尾 

          //比较线性表a和b相同位置的元素,取较小的插入到表c末尾 
          if (*pa <= *pb) {
              *pc++ = *pa++;
          }//if 
          else {
              *pc++ = *pb++;
          }//else
     }//while

     //看看线性表a和b中的所有元素是否都处理完了,若没有,处理剩余元素

     //如果线性表a没有处理完,由于线性表a的剩余元素已经有序,直接将它们插入表c就可以了 
     while (pa <= pa_last) {
          *pc++ = *pa++;      // 插入La的剩余元素
     }//while

     //如果线性表b没有处理完,由于线性表b的剩余元素已经有序,直接将它们插入表c就可以了  
     while (pb <= pb_last) {
          *pc++ = *pb++;      // 插入Lb的剩余元素 
     }//while

     //操作成功 
     return OK;
} // MergeList_Sq 

//8.-----------------------线性表的销毁操作--------------------

/*
    函数:DestoryList_Sq
    参数:SqList &L 被销毁的线性表
    返回值:状态码,操作成功返回OK,操作失败返回ERROR 
    作用:销毁线性表并释放内存空间
*/
void DestoryList_Sq(SqList &L) {

    free(L.elem);
    L.elem = NULL;
    printf("内存空间释放成功!\n");  
} //DestoryList_Sq

//9.-----------------------线性表的排序操作-------------------

/*
    函数:SortList_Sq
    参数:SqList &L 被排序的线性表
    返回值:状态码,操作成功返回OK,操作失败返回ERROR 
    作用:对线性表中的元素进行排序,使其降序排列 
*/
Status SortList_Sq(SqList &L) {

    //将线性表中的元素排序,使用冒泡法,现在没有学过排序的内容,
    //此段代码我当时也是从网上找的,看不懂的话先忽略它 
    /*传统冒泡排序中每一趟排序操作只能找到一个最大值或最小值,
      我们考虑利用在每趟排序中进行正向和反向两遍冒泡的方法
      一次可以得到两个最终值(最大者和最小者),从而使排序趟数几乎减少了一半*/ 

    //检查线性表是否为空表,对空表进行排序操作没有意义
    //if(ListIsEmpty_Sq(L)) <=> if(ListIsEmpty_Sq(L) != 0)
    if(ListIsEmpty_Sq(L)) { 
        return ERROR; 
    }//if

    //设置变量的初始值 
    int low = 0;   
    int high = L.length-1;  
    int tmp, j;  
    while (low < high) {

        //正向冒泡,找到最大者 
        for (j = low; j < high; ++j) {  
            if (L.elem[j] > L.elem[j + 1]) {  
                tmp = L.elem[j]; 
                L.elem[j] = L.elem[j + 1];
                L.elem[j + 1] = tmp;  
            }//if
        }//for

        //修改high值, 前移一位 
        --high;  

        //反向冒泡,找到最小者
        for (j = high; j > low; --j) {   
            if (L.elem[j] < L.elem[j - 1]) {  
                tmp = L.elem[j]; 
                L.elem[j] = L.elem[j - 1];
                L.elem[j - 1] = tmp;  
            }//if
        }//for

        //修改low值,后移一位
        ++low;      
    }  
} //SortList_Sq

//10.----------------------线性表的输出操作------------------

/*
    函数:Print
    参数:ElemType e 被访问的元素 
    返回值:状态码,操作成功返回OK,操作失败返回ERROR 
    作用:访问元素e的函数,通过修改该函数可以修改元素访问方式,
          该函数使用时需要配合遍历函数一起使用。 
*/
Status Print(ElemType e){  // 元素访问函数

    //指定元素的访问方式是控制台打印输出 
    printf("%6.2f ", e);

    //操作成功 
    return OK;
}//Print

/*
    函数:ListTraverse_Sq
    参数:SqList L 顺序表L 
          Status(* visit)(ElemType) 函数指针,指向元素访问函数。 
    返回值:状态码,操作成功返回OK,操作失败返回ERROR 
    作用:调用元素访问函数完成线性表的遍历,所谓遍历就是逐一访问线性表中的每个元素。 
*/
Status ListTraverse_Sq(SqList L, Status(* visit)(ElemType)){

    //i声明在这里不是好的写法,应该将i写在for循环中,有利于缩短i的作用域,及早回收其内存空间。
    //但是由于C语言不兼容这种写法,考虑到兼容性所以将i写在外面。(C++支持这种写法)
    int i;

    //调用元素访问函数逐个访问线性表中的每个元素 
    for(i = 0; i < L.length; ++i){

        //if(!visit(L.elem[i])) <=> if(visit(L.elem[i]) != ERROR) 
        if(!visit(L.elem[i])) { 
            return ERROR; //如果访问某个元素失败则退出 
        }//if 
    }//for

    //便利完成后打印空行,作用是在控制台输出时能够区分开不同的输出
    //使输出清楚美观 
    printf("\n");
    return OK;
}//ListTraverse_Sq


//***************************************主函数******************************************** 
int main(int argc, char *argv[]){ 

    SqList L1, L2, L3;  //声明三个线性表 
    int i;              //i代表元素的位序 
    ElemType e;         //e用于传入和保存元素的值 

    printf("*******************************线性顺序表测试程序*******************************\n");

    //---------------------------------测试初始化功能----------------------------------
    printf("---------------------------------测试初始化功能---------------------------------\n");   
    printf("->初始化线性表L1\n");  
    InitList_Sq(L1, LIST_INIT_SIZE);             //初始化线性表1 
    ListInput_Sq(L1);  //为L1中的元素赋值
    printf("恭喜您,线性表L1初始化并赋值完毕!\n\n");

    printf("->初始化线性表L2\n");
    InitList_Sq(L2, LIST_INIT_SIZE);             //初始化线性表2 
    ListInput_Sq(L2);  //为L2中的元素赋值
    printf("恭喜您,线性表L2初始化并赋值完毕!\n\n");

    //-----------------------------测试输出功能---------------------------------------
    printf("----------------------------------测试输出功能----------------------------------\n"); 
    printf("初始化操作之后L1、L2的元素为:\n");
    printf("->输出线性表L1的所有元素:\n");
    ListTraverse_Sq(L1, Print);                           //在执行其他操作之前先输出一遍所有元素,以供参考 
    printf("->输出线性表L2的所有元素:\n");
    ListTraverse_Sq(L2, Print);

    //-----------------------------测试插入功能---------------------------------------
    printf("\n----------------------------------测试插入功能----------------------------------\n"); 

    printf("->现在为L1插入元素\n");                        //为线性表L1插入一个元素 
    printf("您想在线性表L1的哪个位置之前插入值?\n");
    scanf("%d", &i);
    printf("您想在线性表L1的该位置之前插入的值为多少?\n");
    scanf("%f", &e);
    ListInsert_Sq(L1,i,e);
    printf("执行插入操作后线性表L1的所有元素为:\n");      //输出执行操作后的线性表,以便与原始结果对比 
    ListTraverse_Sq(L1,Print);

    printf("->现在为L2插入元素\n");
    printf("您想在线性表L2的哪个位置之前插入值?\n");      //为线性表L2插入一个元素
    scanf("%d", &i);
    printf("您想在线性表L2的该位置之前插入的值为多少?\n");
    scanf("%f", &e);
    ListInsert_Sq(L2, i, e);
    printf("执行插入操作后线性表L2的所有元素为:\n");     //输出执行操作后的线性表,以便与原始结果对比 
    ListTraverse_Sq(L2, Print);
    printf("\n插入操作执行完毕!\n\n");

    //-----------------------------测试删除功能---------------------------------------
    printf("----------------------------------测试删除功能----------------------------------\n");

    printf("->现在在L1中删除元素\n");                        //在L1中删除一个元素 
    printf("您想在线性表L1的哪个位置之前删除值?\n");
    scanf("%d", &i);
    ListDelete_Sq(L1, i, e);
    printf("被删除的元素为%f\n", e);
    printf("执行删除操作后线性表L1的所有元素为:\n");      //输出执行操作后的线性表,以便与原始结果对比 
    ListTraverse_Sq(L1, Print);

    printf("->现在在L2中删除元素\n");                        //在L2中删除一个元素 
    printf("您想在线性表L2的哪个位置之前删除值?\n");
    scanf("%d", &i);
    ListDelete_Sq(L2, i, e);
    printf("被删除的元素为%f\n", e);
    printf("执行删除操作后线性表L2的所有元素为:\n");      //输出执行操作后的线性表,以便与原始结果对比 
    ListTraverse_Sq(L2, Print);
    printf("\n删除操作执行完毕!\n\n");

    //-----------------------------测试查找功能---------------------------------------
    printf("----------------------------------测试查找功能----------------------------------\n"); 
    printf("您想在线性表L1中查找的值为:\n");
    scanf("%f", &e);
    i = LocateElem_Sq(L1, e, compare);
    if(i == 0){ 
        printf("对不起,没有找到您输入的元素!\n");
    }//if 
    else {
        printf("恭喜,找到啦!您想要的元素在表中的位序为%d\n",i); 
    }//else

    printf("您想在线性表L2中查找的值为:\n");
    scanf("%f", &e);
    i = LocateElem_Sq(L2, e, compare);
    if(i == 0) {
        printf("对不起,没有找到您输入的元素!\n");
    }//if
    else {
        printf("恭喜,找到啦!您想要的元素在表中的位序为%d\n", i);
    }//else

    printf("\n查找操作执行完毕!\n\n");

    //---------------------------------测试排序功能---------------------------------------
    printf("----------------------------------测试排序功能----------------------------------\n"); 
    printf("排序前 L1、L2的元素为:\n");
    printf("->线性表L1的所有元素:\n");
    ListTraverse_Sq(L1, Print);                           //在执行操作之前先输出一遍所有元素,以供参考 
    printf("->线性表L2的所有元素:\n");
    ListTraverse_Sq(L2, Print);

    SortList_Sq(L1);                            //分别对L1和L2进行排序 
    SortList_Sq(L2); 

    printf("排序后 L1、L2的元素为:\n");
    printf("->线性表L1的所有元素:\n");
    ListTraverse_Sq(L1, Print);                           //执行操作之后再输出一遍所有元素
    printf("->线性表L2的所有元素:\n");
    ListTraverse_Sq(L2, Print);
    printf("\n排序操作执行完毕!\n\n");

    //-----------------------------测试归并(合并)功能---------------------------------------
    printf("----------------------------------测试归并功能----------------------------------\n"); 
    printf("->初始化线性表L3\n");
    InitList_Sq(L3, L1.listsize + L2.listsize);         //初始化线性表3,空间大小为L1与L2的和,但不给元素赋值
    printf("线性表L3初始化成功!开始归并操作\n\n");
    MergeList_Sq(L1, L2, L3); 
    printf("->线性表L3的所有元素:\n");
    ListTraverse_Sq(L3, Print); 
    printf("归并操作执行完毕!\n\n");

    //--------------------------------测试销毁功能------------------------------------------
    printf("----------------------------------测试销毁功能----------------------------------\n");
    printf("->销毁线性表L1:");
    DestoryList_Sq(L1); 
    printf("->销毁线性表L2:");
    DestoryList_Sq(L2);
    printf("->销毁线性表L3:");
    DestoryList_Sq(L3);
    printf("销毁操作执行完毕!\n\n");

    printf("所有操作执行完毕,测试成功!\n"); 
    return 0;   
}

看一下程序的运行结果:

*******************************线性顺序表测试程序*******************************
---------------------------------测试初始化功能---------------------------------
->初始化线性表L1
内存申请成功!
线性表创建成功!
您想输入几个元素,请输入个数,最多不可以超过:100
5
请输入线性表L的元素,中间用空格隔开,最多不可以超过100个元素
1 45 7 89 6
该线性表初始化操作已完成!
恭喜您,线性表L1初始化并赋值完毕!

->初始化线性表L2
内存申请成功!
线性表创建成功!
您想输入几个元素,请输入个数,最多不可以超过:100
10
请输入线性表L的元素,中间用空格隔开,最多不可以超过100个元素
45 75 24 16 23 45 89 62 51 44
该线性表初始化操作已完成!
恭喜您,线性表L2初始化并赋值完毕!

----------------------------------测试输出功能----------------------------------
初始化操作之后L1、L2的元素为:
->输出线性表L1的所有元素:
  1.00  45.00   7.00  89.00   6.00
->输出线性表L2的所有元素:
 45.00  75.00  24.00  16.00  23.00  45.00  89.00  62.00  51.00  44.00

----------------------------------测试插入功能----------------------------------
->现在为L1插入元素
您想在线性表L1的哪个位置之前插入值?
2
您想在线性表L1的该位置之前插入的值为多少?
55
执行插入操作后线性表L1的所有元素为:
  1.00  55.00  45.00   7.00  89.00   6.00
->现在为L2插入元素
您想在线性表L2的哪个位置之前插入值?
6
您想在线性表L2的该位置之前插入的值为多少?
33
执行插入操作后线性表L2的所有元素为:
 45.00  75.00  24.00  16.00  23.00  33.00  45.00  89.00  62.00  51.00  44.00

插入操作执行完毕!

----------------------------------测试删除功能----------------------------------
->现在在L1中删除元素
您想在线性表L1的哪个位置之前删除值?
4
被删除的元素为7.000000
执行删除操作后线性表L1的所有元素为:
  1.00  55.00  45.00  89.00   6.00
->现在在L2中删除元素
您想在线性表L2的哪个位置之前删除值?
2
被删除的元素为75.000000
执行删除操作后线性表L2的所有元素为:
 45.00  24.00  16.00  23.00  33.00  45.00  89.00  62.00  51.00  44.00

删除操作执行完毕!

----------------------------------测试查找功能----------------------------------
您想在线性表L1中查找的值为:
55
恭喜,找到啦!您想要的元素在表中的位序为2
您想在线性表L2中查找的值为:
99
对不起,没有找到您输入的元素!

查找操作执行完毕!

----------------------------------测试排序功能----------------------------------
排序前 L1、L2的元素为:
->线性表L1的所有元素:
  1.00  55.00  45.00  89.00   6.00
->线性表L2的所有元素:
 45.00  24.00  16.00  23.00  33.00  45.00  89.00  62.00  51.00  44.00
排序后 L1、L2的元素为:
->线性表L1的所有元素:
  1.00   6.00  45.00  55.00  89.00
->线性表L2的所有元素:
 16.00  23.00  24.00  33.00  44.00  45.00  45.00  51.00  62.00  89.00

排序操作执行完毕!

----------------------------------测试归并功能----------------------------------
->初始化线性表L3
内存申请成功!
线性表创建成功!
线性表L3初始化成功!开始归并操作

->线性表L3的所有元素:
  1.00   6.00  16.00  23.00  24.00  33.00  44.00  45.00  45.00  45.00  51.00  55.00  62.00  89.00  89.00
归并操作执行完毕!

----------------------------------测试销毁功能----------------------------------
->销毁线性表L1:内存空间释放成功!
->销毁线性表L2:内存空间释放成功!
->销毁线性表L3:内存空间释放成功!
销毁操作执行完毕!

所有操作执行完毕,测试成功!

--------------------------------
Process exited with return value 0
Press any key to continue . . .

总结:
本次编程过程中遇到了几个比较麻烦的地方:
1.函数指针,主要用在遍历操作和比较操作中,后面的每个数据结构都会遇上它,要掌握其用法。
2.realloc函数:用于重新分配内存,它可以自动释放原先已分配的内存空间,并且把原有数据拷贝到新的内存空间中,不用我们手动做这些工作。但是要注意,如果重新分配是在改小空间,那就有可能丢数据!

下次的文章内容是单链表程序的实现。希望大家继续关注我的博客,拜拜!

你可能感兴趣的:(学习笔记)