动态顺序表的基本操作

上一篇文章静态顺序表的基本操作
实现了静态顺序表的基本操作,仔细一想,发现静态顺序表好像有缺陷,首先,进程中,需要开辟一大块空间供动态顺序表存储数据用,如果存储的数据不多(结点不多),会浪费很多内存,如果开辟空间比较少,而存储数据较多,就会存在数据存不下的情况,这都不是我们想要的,建立在这样的基础上,动态顺序表的就出现了,先来看一下动态顺序表的结构体:

typedef int DataType;

typedef struct SeqList
{
    DataType* _a;  //数据块指针
    int _size;   // 有效数据个数 
    int _capacity;   // 容量 
}SeqListD;

typedef SeqListD* PSeqListD;

这里的数据块指针是数据在内存中存储的首地址,就像数组的地址一样。

SeqListD.h

#pragma once

#include <stdio.h>
#include <assert.h>
#include <malloc.h>
#include <stdlib.h>

#define INIT_SIZE 10
#define INCREMENT 5

typedef int DataType;

typedef struct SeqList
{
    DataType* _a;  //数据块指针
    int _size;   // 有效数据个数 
    int _capacity;   // 容量 
}SeqListD;

typedef SeqListD* PSeqListD;

//动态顺序表初始化
void SeqListDInit(PSeqListD ps);
//动态顺序表尾插
void SeqListDPushBack(PSeqListD ps, DataType data);
//动态顺序表尾删
void SeqListDPopBack(PSeqListD ps);
//动态顺序表头插
void SeqListDPushFront(PSeqListD ps, DataType data);
//动态顺序表头删
void SeqListDPopFront(PSeqListD ps);
//指定位置插入
void SeqListDInsert(PSeqListD ps, int pos, DataType data);
//指定位置删除
void SeqListDErase(PSeqListD ps, int pos);
//在动态顺序表中查找元素data,找到返回下标,找不到返回-1
int Find(PSeqListD ps, DataType data);
//删除动态顺序表中第一个data元素
void Remove(PSeqListD ps, DataType data);
//删除顺序表中所有data元素
void RemoveAll(PSeqListD ps, DataType data);
//顺序表遍历
void PrintSeqListD(PSeqListD ps);

// 获取元素个数 
int SeqListDSize(PSeqListD ps);

// 获取顺序表的容量 
int SeqListDCapacity(PSeqListD ps);
//判空
int SeqListDEmpty(PSeqListD ps);

// 将顺序表中的元素清空 注意:不改变顺序表空间的大小 
void SeqListDClear(PSeqListD ps);
void SeqListDDestroy(PSeqListD ps);

//检查当前线性表的容量,不够的话申请内存
void CheckCapacity(PSeqListD ps);

//冒泡排序,升序和降序两种版本,用了函数指针
void BubbleSort(PSeqListD ps, int(*cmp)(const void *elem1, const void *elem2));
//选择排序,升序和降序两种版本,用了函数指针
void SelectSort(PSeqListD ps, int(*cmp)(const void *elem1, const void *elem2));
//升序比较
int CmpInAscendingOrder(const void *elem1, const void *elem2);  
//降序比较
int CmpInDescendingOrder(const void *elem1, const void *elem2); 
//二分查找 
int BinarySearch(PSeqListD ps, DataType data); 

SeqListD.c

#include "SeqListD.h"

//检查当前线性表的容量,不够的话申请内存
void CheckCapacity(PSeqListD ps)
{
    //参数检验
    assert(ps);
    if (ps->_size >= ps->_capacity)
    {
        DataType *p = (DataType *)realloc(ps->_a, (ps->_capacity + INCREMENT) * sizeof(DataType));
        if (NULL == p)
        {
            printf("增容失败!\n");
            return;
        }
        else
        {
            ps->_a = p;
            ps->_capacity += INCREMENT;
        }
    }
}
//动态顺序表的初始化
void SeqListDInit(PSeqListD ps)
{
    //参数检验
    assert(ps);
    ps->_a = (DataType *)malloc(sizeof(DataType) * INIT_SIZE);
    if (NULL == ps->_a)
    {
        printf("内存申请失败!!!\n");
        return;
    }
    else
    {
        ps->_size = 0;
        ps->_capacity = INIT_SIZE;
    }
}

//尾插
void SeqListDPushBack(PSeqListD ps, DataType data)
{
    //参数检验
    assert(ps);
    CheckCapacity(ps);
    ps->_a[ps->_size] = data;
    ps->_size++;
}

//尾删
void SeqListDPopBack(PSeqListD ps)
{
    //参数检验
    assert(ps);
    if (0 == ps->_size)
    {
        printf("顺序表已空!\n");
        return;
    }
    else
    {
        ps->_size--;
    }
}

//头插
void SeqListDPushFront(PSeqListD ps, DataType data)
{
    int i = 0;
    //参数检验
    assert(ps);

    CheckCapacity(ps);
    //先把原来所有元素后移
    i = ps->_size;
    while (i != 0)
    {
        ps->_a[i] = ps->_a[i-1];
        i--;
    }
    //再把元素插到第一个位置
    ps->_a[0] = data;
    //插入之后,让size++
    ps->_size++;
}

//动态顺序表头删
void SeqListDPopFront(PSeqListD ps)
{
    int i = 0;
    // 参数检验
    assert(ps);

    while (i < ps->_size)
    {
        ps->_a[i] = ps->_a[i + 1];
        i++;
    }
    //移除之后让size--
    ps->_size--;
}

//顺序表指定位置插入
void SeqListDInsert(PSeqListD ps, int pos, DataType data)
{
    int i = 0;

    //参数检验
    assert(ps);
    if ((pos < 1) || (pos > ps->_size))
    {
        printf("pos位置不合法!\n");
        return;
    }
    else
    {
        int turepos = pos - 1;
        i = ps->_size;
        while (i != turepos)
        {
            ps->_a[i] = ps->_a[i-1];
            i--;
        }
        ps->_a[turepos] = data;
        ps->_size++;
    }
}

//指定位置删除
void SeqListDErase(PSeqListD ps, int pos)
{
    int i = 0;

    //参数检验
    assert(pos);
    if ((pos < 1) || (pos > ps->_size))
    {
        printf("pos位置不合法!\n");
        return;
    }
    else
    {
        i = pos - 1;
        while (i < ps->_size - 1)
        {
            ps->_a[i] = ps->_a[i+1];
            i++;
        }
        ps->_size--;
    }
}

//在动态顺序表中查找元素data,找到返回下标,找不到返回-1
int Find(PSeqListD ps, DataType data)
{
    int i = 0;
    //参数检验
    assert(ps);

    while (i < ps->_size)
    {
        if (data == ps->_a[i])
        {
            return i;
        }
        i++;
    }
    return -1;
}

//删除动态顺序表中第一个data元素
void Remove(PSeqListD ps, DataType data)
{
    int ret_Find = 0;
    //参数检验
    assert(ps);
    ret_Find = Find(ps, data);
    if (-1 == ret_Find)
    {
        printf("顺序表中无 %d 元素\n", data);
        return;
    }
    else
    {
        //方法一:利用SeqListDErase(ps, ret_Find+1)函数
        //SeqListDErase(ps, ret_Find+1);
        //方法二
        int i = ret_Find;
        while (i < ps->_size-1)
        {
            ps->_a[i] = ps->_a[i + 1];
            i++;
        }
        ps->_size--;
    }
}

//删除顺序表中所有data元素
void RemoveAll(PSeqListD ps, DataType data)
{
    int i = 0;//i当作循环变量,遍历顺序表
    int count = 0;//统计在顺序表中删了多少个值data的元素个数
    int index = 0;//辅助删除的变量
    //参数检验
    assert(ps);
    while (i < ps->_size)
    {
        if (data == ps->_a[i])
        {
            //遇到值为data的元素,跳过,并让计数器+1
            i++;
            count++;
            continue;
        }
        ps->_a[index] = ps->_a[i];//依次赋值
        i++;
        index++;
    }
    //最后让用来统计顺序表中元素个数的size-count,得到现在顺序表中所有元素个数
    ps->_size -= count;
    printf("动态顺序表中所有值为%d的元素已删除\n", data);
}

//顺序表遍历
void PrintSeqListD(PSeqListD ps)
{
    int i = 0;
    //参数检验
    assert(ps);

    printf("顺序表中所有元素:\n");
    while (i < ps->_size)
    {
        printf("%d ", ps->_a[i]);
        i++;
    }
    printf("\n");
}

// 获取元素个数 
int SeqListDSize(PSeqListD ps)
{
    assert(ps);

    return ps->_size;
}

// 获取顺序表的容量 
int SeqListDCapacity(PSeqListD ps)
{
    assert(ps);

    return ps->_capacity;
}

// 判空
int SeqListDEmpty(PSeqListD ps)
{
    assert(ps);

    return ps->_size;
}

// 将顺序表中的元素清空 注意:不改变顺序表空间的大小 
void SeqListDClear(PSeqListD ps)
{
    assert(ps);

    ps->_size = 0;
}

//动态顺序表销毁
void SeqListDDestroy(PSeqListD ps)
{
    assert(ps);

    free(ps->_a);
    ps->_a = NULL;
    ps->_capacity = 0;
    ps->_size = 0;
}

//升序比较 
int CmpInAscendingOrder(const void *elem1, const void *elem2)
{
    return *(int *)elem1 - *(int *)elem2;
}

//降序比较 
int CmpInDescendingOrder(const void *elem1, const void *elem2)
{
    return *(int *)elem2 - *(int *)elem1;
} 

//交换
void swap(DataType *a, DataType *b)
{
    DataType temp = *a;
    *a = *b;
    *b = temp;
}  

//冒泡排序,升序和降序两种版本,用了函数指针  
void BubbleSort(PSeqListD ps, int(*cmp)(const void *elem1, const void *elem2))
{
    int i = 0;
    int j = 0;
    int flag = 0; // 设置一个标签,如果一次循环中flag值始终,没改变,证明数组内元素已经有序
    //参数检验
    assert(ps);
    for (i = 0; i < ps->_size - 1; i++)
    {
        flag = 0; // 把flag重置为0,方便下一次循环里有没有交换元素
        for (j = 0; j < ps->_size - 1 - i; j++)
        {
            if (cmp(&ps->_a[j], &ps->_a[j + 1]) > 0)
            {
                swap(&ps->_a[j], &ps->_a[j + 1]);
                flag = 1;
            }
        }
        if (flag == 0)
        {
            break;
        }
    }

}

//选择排序,升序和降序两种版本,用了函数指针
void SelectSort(PSeqListD ps, int(*cmp)(const void *elem1, const void *elem2))
{
    int i = 0;
    int j = 0;
    int pos = 0; // 用来记录最值位置
    //参数检验
    assert(ps);

    for (i = 0; i < ps->_size - 1; i++)
    {
        pos = i;
        for (j = i + 1; j < ps->_size; j++)
        {
            if (cmp(&ps->_a[j], &ps->_a[pos]) < 0)
            {
                pos = j;
            }
        }
        if (i != pos)
        {
            swap(&ps->_a[i], &ps->_a[pos]);
        }
    }
}

//二分查找
int BinarySearch(PSeqListD ps, DataType data)
{
    int left = 0;
    int right = 0;
    int mid = 0;
    // 参数检验
    assert(ps);

    right = ps->_size - 1;
    while (left <= right)
    {
        mid = left + (right - left) / 2;
        if (data < ps->_a[mid])
        {
            right = mid - 1;
        }
        else if (data > ps->_a[mid])
        {
            left = mid + 1;
        }
        else
        {
            return mid;
        }
    }
    return -1;
}

测试函数
1.TestSeqListDInit_PushBack_PopBack
测试动态顺序表的初始化、尾插和尾删操作

#include "SeqListD.h"

void TestSeqListDInit_PushBack_PopBack()
{
    SeqListD s;//定义顺序表
    SeqListDInit(&s);//初始化
    SeqListDPushBack(&s, 1);//尾插元素
    SeqListDPushBack(&s, 2);
    SeqListDPushBack(&s, 3);
    SeqListDPushBack(&s, 4);
    PrintSeqListD(&s);//顺序表遍历

    SeqListDPopBack(&s);//尾删一个元素
    PrintSeqListD(&s);//顺序表遍历


}

//主函数
int main()
{
    TestSeqListDInit_PushBack_PopBack();
    system("pause");
    return 0;
}

测试结果:
顺序表初始化、尾插、尾删测试结果
2.TestSeqListDPushFront_PopFront
测试动态顺序表的头插和头删操作

#include "SeqListD.h"

void TestSeqListDPushFront_PopFront()
{
    SeqListD s;//定义顺序表
    SeqListDInit(&s);//初始化
    SeqListDPushFront(&s, 4);//头插元素
    SeqListDPushFront(&s, 3);
    SeqListDPushFront(&s, 2);
    SeqListDPushFront(&s, 1);
    PrintSeqListD(&s);//顺序表遍历

    SeqListDPopFront(&s);//头删一个元素
    PrintSeqListD(&s);//顺序表遍历
}

//主函数
int main()
{
    TestSeqListDPushFront_PopFront();
    system("pause");
    return 0;
}

测试结果:
动态顺序表头插、头删测试结果
3.TestSeqListDInsert_Erase
测试动态顺序表指定位置插入和删除

#include "SeqListD.h"

void TestSeqListDInsert_Erase()
{
    SeqListD s;//定义顺序表
    SeqListDInit(&s);//初始化
    SeqListDPushBack(&s, 1);//尾插元素
    SeqListDPushBack(&s, 2);
    SeqListDPushBack(&s, 4);
    SeqListDPushBack(&s, 5);
    PrintSeqListD(&s);//顺序表遍历

    SeqListDInsert(&s, 3, 3);//指定位置插入
    PrintSeqListD(&s);//顺序表遍历

    SeqListDErase(&s, 5);//指定位置删除
    PrintSeqListD(&s);//顺序表遍历
}

//主函数
int main()
{
    TestSeqListDInsert_Erase();
    system("pause");
    return 0;
}

测试结果:
动态顺序表指定位置插入和删除测试结果
4.TestSeqListDRemove_RemoveAll
测试删除顺序表中某元素的第一次出现和删除顺序表中的所有出现

#include "SeqListD.h"

void TestSeqListDRemove_RemoveAll()
{
    SeqListD s;// 定义顺序表
    SeqListDInit(&s);// 初始化
    SeqListDPushBack(&s, 1);// 尾插元素
    SeqListDPushBack(&s, 2);
    SeqListDPushBack(&s, 3);
    SeqListDPushBack(&s, 2);
    SeqListDPushBack(&s, 4);
    SeqListDPushBack(&s, 2);
    SeqListDPushBack(&s, 5);
    PrintSeqListD(&s);// 顺序表遍历

    Remove(&s, 2);// 删除顺序表中的第一个值为2的元素
    PrintSeqListD(&s);// 顺序表遍历

    RemoveAll(&s, 2);// 删除顺序表中所有值为2的元素
    PrintSeqListD(&s);// 顺序表遍历
}

//主函数
int main()
{
    TestSeqListDRemove_RemoveAll();
    system("pause");
    return 0;
}

测试结果:
测试结果
5.TestSeqListDSize_Capacity_Empty_Clear_Destorday
测试获取顺序表个数、顺序表容量、判断顺序表是否为空、顺序表清空、摧毁顺序表

#include "SeqListD.h"

void TestSeqListDSize_Capacity_Empty_Clear_Destorday()
{
    SeqListD s;//定义顺序表
    int ret_Size = 0;
    int ret_Capacity = 0;
    int ret_Empty = 0;
    SeqListDInit(&s);//初始化
    SeqListDPushBack(&s, 1);//尾插元素
    SeqListDPushBack(&s, 2);
    SeqListDPushBack(&s, 3);
    SeqListDPushBack(&s, 4);
    PrintSeqListD(&s);//遍历顺序表

    ret_Size = SeqListDSize(&s);//获取顺序表中元素个数
    printf("Size = %d\n", ret_Size);

    ret_Capacity = SeqListDCapacity(&s);//获取顺序表的容量
    printf("Catacity = %d\n", ret_Capacity);

    ret_Empty = SeqListDEmpty(&s);//判空
    if (0 == ret_Empty)
    {
        printf("顺序表为空\n");
    }
    else
    {
        printf("顺序表不为空\n");
    }

    SeqListDClear(&s);//清空顺序表
    SeqListDDestroy(&s);//摧毁顺序表


}

//主函数
int main()
{
    TestSeqListDSize_Capacity_Empty_Clear_Destorday();
    system("pause");
    return 0;
}

测试结果:
这里写图片描述
6.TestSeqListDBubbleSort_SelectSort
测试冒泡排序和选择排序

#include "SeqListD.h"

void TestSeqListDBubbleSort_SelectSort()
{
    SeqListD s;
    int ret_BubbleFind = 0;
    int ret_SelectFind = 0;
    SeqListDInit(&s);
    SeqListDPushBack(&s, 1);
    SeqListDPushBack(&s, 3);
    SeqListDPushBack(&s, 2);
    SeqListDPushBack(&s, 7);
    SeqListDPushBack(&s, 4);
    SeqListDPushBack(&s, 5);
    SeqListDPushBack(&s, 8);
    SeqListDPushBack(&s, 6);
    PrintSeqListD(&s);

    BubbleSort(&s, CmpInAscendingOrder);
    PrintSeqListD(&s);

    ret_BubbleFind = BinarySearch(&s, 2);
    if (-1 == ret_BubbleFind)
    {
        printf("顺序表中无此元素\n");
    }
    else
    {
        printf("找到了,下标为%d\n", ret_BubbleFind);
    }

    BubbleSort(&s, CmpInDescendingOrder);
    PrintSeqListD(&s);

    SelectSort(&s, CmpInAscendingOrder);
    PrintSeqListD(&s);

    ret_SelectFind = BinarySearch(&s, 2);
    if (-1 == ret_SelectFind)
    {
        printf("顺序表中无此元素\n");
    }
    else
    {
        printf("找到了,下标为%d\n", ret_SelectFind);
    }

    SelectSort(&s, CmpInDescendingOrder);
    PrintSeqListD(&s);

    SeqListDDestroy(&s);
}

int main()
{
    TestSeqListDBubbleSort_SelectSort();
    system("pause");
    return 0;
}

测试结果:
这里写图片描述

扫描二维码关注公众号,回复: 154196 查看本文章

猜你喜欢

转载自blog.csdn.net/eric_qiushui/article/details/80099547