线性表的顺序表示及实现

经过一个星期的学习,主要学习鲍春山的视频教程和严蔚敏的数据结构,将线性表的学习记录下来,和大家分享。如有错误,不吝指正! —-2017.10

一、概念

线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
逻辑关系为线性,物理关系也为线性。因此本次实验使用数组描述数据结构中的顺序存储结构。

//————-线性表的动态分配顺序存储结构————

#define SEQLIST_INIT_SIZE 8   //线性表存储空间的初始分配量
#define INC_SIZE          3   //线性表存储空间的分配增量
typedef struct SeqList
{
    ElemType * base;     //存储空间基址
    int        capacity; //当前分配的存储容量(以sizeof(ElemType)为单位)
    int        size;     // 实际长度
}SeqList;

在上述定义中,数组指针base表示线性表的基地址,capacity表示顺序表当前分配的存储空间的大小,size表示线性表的当前长度。

二、函数实现的难点

由于直接上代码并没有学习的收获,因此这里专门开辟一个节点,对自己每个函数实现时需要重点考虑的部分进行剖析,无论自己还是他人,后面在此基础上修改时,也能快速明白难点所在。
这里依据函数声明,依次分析:

void InitSeqList(SeqList *list); //initiation

该函数本质上是对定义的结构体对象进行初始化。使用malloc动态分配一个长度为SEQLIST_INIT_SIZE (即8)的存储空间,得到基地址为base。同时初始化存储容量和当前线性表的长度。

bool IncSeqList(SeqList *list);  //increase

该函数使用realloc函数将已经malloc的内存块重新扩展加长为SEQLIST_INIT_SIZE +INC_SIZE(即8+3)的存储空间,得到新的基地址newbase。同时更新新的容量大小。
如果增分配成功,返回true;否则返回false。后面我们会利用该标志位确定是否增分配成功。

void push_back(SeqList *List,ElemType item); //tail insert
void push_front(SeqList *List,ElemType item); //head insert
void insert_pos(SeqList *List,int pos,ElemType item); //insert value at pos

这三个函数总体来说都是插入功能,分别是尾插、头插、特定位置(下标)插入。
1) 插入时,我们需要考虑当前原分配空间是否已满,如果满了并且增分配失败,则报错,其他情况都继续执行。

    //原分配空间已满,且增配空间失败
    if(List->size >= List->capacity && !IncSeqList(List))
    {
        printf("SeqList has full,value %d can't insert tail\n",item);
        return ;
    }

2) 插入后,表示在当前的序列中多添加了一个元素,因此当前长度加一
3) 如果插入后,需要移动元素(左移或右移),均需要明确下标的具体含义以及所采用的准则。
这里下标的定义size理解:1,当前线性表中元素的个数 2,即将插入值的下标。注意是即将。
这里假定的准则是:左值的下标不做局部操作,仅对右值下标进行操作。什么意思呢?举例:

    //从下标1开始全部左移
    for(int i=0;isize-1;i++)
    {
        List->base[i] = List->base[i+1] ;
    }

这里我们可以看到,线性表下标本质上是[0,size-1]。因此我们当左值范围从i=0开始,右值局部操作为i+1。
也就是说,我们for循环中对i的计数正好就是左值的下标,仅仅对右值左局部操作。即不会出现下面这种操作:

   List->base[i+1] = List->base[i] ;  //不采用
void pop_back(SeqList *List); //pop tail
void pop_front(SeqList *List); //pop head
void delete_pos(SeqList *List,int pos); //delete value at pos

这三个函数总体来说是删除一个元素。因此我们需要考虑当前元素是否为空(List->size == 0),如果为空,则无法弹出元素。
同上,如果输入参数有位置下标,则需要判断下标是否合法。

int  find_val(SeqList *List,ElemType item); //find the pos of value
void delete_val(SeqList *List,ElemType item); //delete value

查找某个数是否存在,如果存在则返回第一个下标。
删除某个数,利用到find_val查找第一个元素下标,然后根据该下标进行删除元素。

void sort(SeqList *List); //Ascend sort
void reverse(SeqList *List); //reverse

sort对序列进行升序排列,这里使用了选择排序,每次在无序队列中”选择”出最小值,放到有序队列的最前面。
reverse对序列进行反转,这里并没有借助辅助空间,而是在原空间进行反转(in space)。

void show_list(SeqList *List); //show
int  length(SeqList * List); //the length of SeqList
void clear(SeqList *List); //clear
void destroy(SeqList *List); //destroy

这几个函数并没有太大的技巧。主要完成打印显示、返回当前序列长度、清除序列(List->size=0即可)、销毁序列(一般main函数退出时调用)。

三、代码

SeqList.h


#ifndef __SEQLIST_H__
#define __SEQLIST_H__

#include 
#include 
#include 


#define SEQLIST_INIT_SIZE 8
#define INC_SIZE          3

typedef int ElemType;


typedef struct SeqList
{
    ElemType * base;     //存储空间基址
    int        capacity; //当前分配的存储容量(以sizeof(ElemType)为单位)
    int        size;     // 实际长度
}SeqList;


//function declaration
void InitSeqList(SeqList *list); //initiation
bool IncSeqList(SeqList *list);  //increase

void push_back(SeqList *List,ElemType item); //tail insert
void show_list(SeqList *List); //show
void push_front(SeqList *List,ElemType item); //head insert
void pop_back(SeqList *List); //pop tail
void pop_front(SeqList *List); //pop head

void insert_pos(SeqList *List,int pos,ElemType item); //insert value at pos
int  find_val(SeqList *List,ElemType item); //find the pos of value
int  length(SeqList * List); //the length of SeqList
void delete_pos(SeqList *List,int pos); //delete value at pos
void delete_val(SeqList *List,ElemType item); //delete value

void sort(SeqList *List); //Ascend sort
void reverse(SeqList *List); //reverse
void clear(SeqList *List); //clear
void destroy(SeqList *List); //destroy
#endif // __SEQLIST_H__

SeqList.cpp

#include "SeqList.h"

void InitSeqList(SeqList *list)
{
    list->base = (ElemType*)malloc(sizeof(ElemType)*SEQLIST_INIT_SIZE);
    assert(list->base != NULL);

    list->capacity = SEQLIST_INIT_SIZE;
    list->size =0;
}

//success: true
bool IncSeqList(SeqList *list)
{
    ElemType *newbase = (ElemType*)realloc(list->base,sizeof(ElemType)*(SEQLIST_INIT_SIZE+INC_SIZE));
    if(newbase == NULL)
    {
        printf("Insufficient memory space allocation\n");
        return false;
    }

    list->base = newbase;
    list->capacity = SEQLIST_INIT_SIZE + INC_SIZE;

    return true;
}

//insert
void push_back(SeqList *List,ElemType item)
{

    //原分配空间已满,且增配空间失败
    if(List->size >= List->capacity && !IncSeqList(List))
    {
        printf("SeqList has full,value %d can't insert tail\n",item);
        return ;
    }
    List->base[List->size] = item;

    List->size++;

}
void push_front(SeqList *List,ElemType item)
{
    //原分配空间已满,且增配空间失败
    if(List->size >= List->capacity && !IncSeqList(List))
    {
        printf("SeqList has full,value %d can't insert head\n",item);
        return ;
    }

    //从0开始全部右移1位(如果没有元素,不进入循环)
    for(int i=List->size;i >0; i--)
    {
        List->base[i] = List->base[i-1];
    }

    //坐标为0,插入新元素
    List->base[0] = item;

    //添加了新元素,当前计数+1
    List->size++;
    //printf("hello world \n");
}

void pop_back(SeqList *List)
{
    //如果没有元素
    if(List->size == 0)
    {
        printf("no element,can not delete\n");
        return ;
    }
    printf("delete tail value:%d\n",List->base[List->size-1]);

    //删除(最后)一个元素,当前计数自减
    List->size--;
}
void pop_front(SeqList *List)
{
    //如果没有元素
    if(List->size == 0)
    {
        printf("no element,can not delete\n");
        return ;
    }
    printf("delete head value:%d\n",List->base[0]);

    //从下标1开始全部左移
    for(int i=0;i<List->size-1;i++)
    {
        List->base[i] = List->base[i+1] ;
    }
    //删除(第)一个元素,当前计数自减
    List->size--;
}

void insert_pos(SeqList *List,int pos,ElemType item)
{
    //判断位置是否合法(为0,即头插; 为size即尾插)
    if(pos<0 || pos>List->size)
    {
        printf("insert pos illegal,can't insert\n");
        return ;
    }

    //原分配空间已满,且增配空间失败
    if(List->size >= List->capacity && !IncSeqList(List) )
    {
        printf("SeqList has full,value %d can't insert at pos \n",item);
        return ;
    }

    //size为即将插入位置,全部左移,留出pos
    for(int i=List->size; i>pos; i--)
    {
        List->base[i] = List->base[i-1];
    }

    List->base[pos] = item;

    List->size++;
}

int find_val(SeqList *List,ElemType item)
{
   //找到第一个匹配值的坐标
   for(int i=0;i<List->size;i++)
   {
       if(item == List->base[i])
       {
           return i;
       }
   }

   return -1;
}

int  length(SeqList * List)
{
    return List->size;
}

void  delete_pos(SeqList *List,int pos)
{
    if(pos <0 || pos >= List->size)
    {
        printf("delete pos illegal,can't delete\n");
        return ;
    }

    //从pos+1处全部左移
    for(int i=pos; i<List->size-1;i++)
    {
        List->base[i] = List->base[i+1];
    }

    List->size--;
}

void delete_val(SeqList *List,ElemType item)
{
    int pos;
    pos = find_val(List,item);

    if(pos < 0 )
    {
        printf("value %d not found!\n",item);
        return ;
    }
    delete_pos(List,pos);
}
/*选择排序:每次在无序队列中"选择"出最小值,放到有序队列的最前*/
void sort(SeqList *List)
{
    if(List->size == 0 || List->size ==1)
        return;

    int temp;
    int min;
    for(int i=0; i<List->size; i++)
    {
        min = i;
        for(int j= i+1;j<List->size;j++)
        {
            if (List->base[j] < List->base[min])
                min=j;
        }

        //交换最小数
        if(min != i)
        {
            temp =  List->base[min];
            List->base[min] =  List->base[i];
            List->base[i] = temp;
        }

    }

}

void reverse(SeqList *List)
{
    int temp;
    for(int i=0; i<List->size/2; i++)
    {
        temp =  List->base[i];
        List->base[i] =  List->base[List->size-1-i];
        List->base[List->size-1-i] = temp;
    }

}

void clear(SeqList *List)
{
    List->size = 0;
}

void destroy(SeqList *List)
{
    free(List->base);
    List->base = NULL;
    List ->capacity = 0;
    List ->size = 0;

    return ;
}
void show_list(SeqList *List)
{
    for(int i=0;i<List->size;i++)
    {
        printf("%d  ",List->base[i]);
    }

    printf("\n");
}

main.cpp

#include "SeqList.h"

int main()
{
    ElemType item;
    SeqList myList;
    InitSeqList(&myList);

    int select = 1;
    int pos=0;
    //int res =0;
    while (select)
    {
        printf("*******************************************\n");
        printf("* [1] push_back             [2] push_front \n");
        printf("* [3] show_list             [4] pop_back   \n");
        printf("* [5] pop_front             [6] insert_pos \n");
        printf("* [7] find_value            [8] length     \n");
        printf("* [9] delete_pos            [10] delete_val\n");
        printf("* [11] sort                 [12] reverse \n"  );
        printf("* [13] clear                [14*] destroy \n" );
        printf("* [0] quit_system                          \n");
        printf("*******************************************\n");
        printf("do some choice:");
        scanf("%d",&select);
        if(select == 0)
            break;
        switch(select)
        {

            case 1:
                printf("tail insert:");
                while(scanf("%d",&item),item != -1)
                {
                    push_back(&myList,item);//尾插
                }
                break;
            case 2:
                printf("head insert:");
                while(scanf("%d",&item),item != -1)
                {
                    push_front(&myList,item);//头插
                }
                break;
            case 3:
                show_list(&myList); //显示
                break;
            case 4:
                pop_back(&myList); //删除最后一个元素(如果有)
                break;
            case 5:
                pop_front(&myList); //删除第一个元素(如果有)
                break;
            case 6:
                 printf("input insert pos>");
                 scanf("%d",&pos);
                 printf("input value>");
                 scanf("%d",&item);
                 //printf("%d %d",pos,item);
                 insert_pos(&myList,pos,item);//在特定下标处插值
                break;
            case 7:
                printf("input find value>");
                scanf("%d",&item);
                pos=find_val(&myList,item);//查找值的下标
                if(pos <0)
                    printf("can not find %d\n",item);
                else
                    printf("find %d at pos %d\n",item,pos);
                break;
            case 8:
                printf("the length of SeqList is %d\n",length(&myList)); //当前长度
                break;
            case 9:
                printf("input delete pos>");
                scanf("%d",&pos);
                delete_pos(&myList,pos); //删除特定下标处值
                break;
            case 10:
                printf("input delete value>");
                scanf("%d",&item);
                delete_val(&myList,item); //删除特定值(找不到值时不会报错)
                break;
            case 11:
                sort(&myList); //升序(选择排序法)
                printf("has ascended sort\n");
                break;
            case 12:
                reverse(&myList);//反转
                printf("has reversed \n");
                break;
            case 13:
                clear(&myList); //清除
                printf("has cleared\n");
                break;
            case 14:
                destroy(&myList);//销毁
                printf("has destroyed\n");
                break;
            default:
                printf("not exist,input again!\n");
                break;

        }

    }
    destroy(&myList);//销毁(程序退出前)
    return 0;
}

四、验证

在main函数中,当我们输入数据时,以-1结尾。
线性表的顺序表示及实现_第1张图片

你可能感兴趣的:(数据结构与算法)