顺序表存储相关操作

顺序表的结构

例如图所示结构(假设开辟了10个空间),按照顺序进行元素的插入在这里插入图片描述

首先创建一个顺序表结构

typedef struct SeqList
{
 ElemType *base;
 size_t capacity;  //容量
 size_t size;      //元素个数
}SeqList;

初始化

#define SEQLIST_DEFAULT_SIZE 8
void SeqListInit(SeqList *plist)   //初始化
{
 assert(plist != NULL);
 plist->capacity = SEQLIST_DEFAULT_SIZE;
 plist->base = (ElemType*)malloc(sizeof(ElemType));
 plist->size = 0;
}

判空判满条件

满----> 元素个数(size)等于顺序表容量(capacity)

bool IsFull(SeqList *plist)       //判满
{
 assert(plist!=NULL);
 return plist->size >= plist->capacity;
}
bool IsEmpty(SeqList *plist)     //判空
{
 assert(plist != NULL);
 return plist->size == 0;
}

顺序表的插入

首先,顺序表中元素的插入方法可以有:
“头插” ----- 从顺序表的开头位置进行插入元素;
“尾插” ----- 从最后一个元素结束的位置进行插入新的元素(当顺序表空间足够大的情况下,不会发生表满无法插入)
“按照元素大小进行插入” ---- 首先需要对顺序表中元素进行排序,在比较大小插入
“按照位置插入” ---- 比如要在下表为 4 的位置进行插入元素,如果后续还有元素则后边元素需要整体后移再插入(不考虑表满情况下)

(一)头插法

例如要将元素 8 插入到顺序表表头的位置: 在这里插入图片描述

思路:
1、先判断表中元素个数与表空间大小的关系(判满),如果表满自动进行扩容,若表不满则可以直接进行插入;2、其次要将元素进行头插,则需要将表中元素整体后移一个空间;

实现方法:

void SeqListPushFront(SeqList *plist, ElemType x)
{  //头插
 assert(plist != NULL);
 if (IsFull(plist) && !_Inc(plist, plist->capacity * 2)) {
  printf("顺序表已满,头插 %d 不能插入.\n", x);
  return;
 }
 for (size_t i = plist->size; i > 0; i--) {
  plist->base[i] = plist->base[i - 1];
 }
 plist->base[0] = x;
 plist->size++;
}

注意:
if 条件判断解释:&& 操作,如果判满条件为真(意味着表已满),那么就该进行自动扩容操作判断;相反,如果判满为假(意味着表未满可以直接插入)则不需要进行后序扩容操作及条件的判断。

其中自动扩容方法
(两种:自己实现;调用库函数)

bool _Inc(SeqList *plist,size_t new_capacity)  //扩容
{
 //code  1
 /*assert(plist != NULL && new_capacity > plist->capacity);
 ElemType *new_base = (ElemType*)realloc(plist->base, sizeof(ElemType)* new_capacity);
 if (new_base == NULL) {
  return false;
 }
 plist->base = new_base;
 plist->capacity = new_capacity;
 return true;*/
 
 assert(plist != NULL && new_capacity > plist->capacity);
 ElemType *new_base = (ElemType*)malloc(sizeof(ElemType)*new_capacity);
 if (new_base == NULL) {
  return false;
 }
 memcpy(new_base, plist->base, sizeof(ElemType)*(plist->capacity));
 free(plist->base);              //释放旧空间
 plist->base = new_base;
 plist->capacity = new_capacity;
 return true;
}

(二)尾插法

如图所示,要将 元素进行尾部插入,不是讲讲将七其直接插入到表的最后一个空间,而是要将插入到的元素紧接着表中最后一个元素的位置开始进行插入。在这里插入图片描述

思路:
同样要先进行判满操作
如果表满则自动开辟空间进行存储,如果不满可以直接进行插入操作,但是需要进行元素的位置移动

实现过程

void SeqListPushBack(SeqList *plist, ElemType x)
{     //尾插
 assert(plist != NULL);
 if (IsFull(plist) && !_Inc(plist,plist->capacity * 2)) {
  printf("顺序表已满,尾插 %d 不能插入.\n", x);
  return;
 }
 plist->base[plist->size++] = x;   //先放入数据,在进行数据个数加一
}

(三)按位置插入
比如想要在 4 这个位置(注意是下标为 4 的位置不是第 4 个空间)进行插入操作
在这里插入图片描述
这种情况下刚好可以直接进行插入不需要元素的移动操作;
在这里插入图片描述
若要插入的位置(第四个位置)有元素存在,咋需要将第四个及以后的元素向后移动一个空间,将第四个位置处空出来,在进行插入操作;(判满)

实现过程
要注意循环条件 i 值的控制(参考图示进行编写代码)

bool SeqListInsertByPos(SeqList *plist, int pos, ElemType x)
{              //按位置插入
 assert(plist != NULL);
 if (IsFull(plist)) {
  printf("顺序表已满,%d 不能在 %d 位置进行插入\n", x, pos);
  return false;
 }
 if (pos < 0 || pos > plist->size) {
  printf("插入的位置 %d 是非法的,%d 不能插入\n", pos, x);
  return false;
 }
 for (size_t i = plist->size; i > pos; --i) {
  plist->base[i] = plist->base[i - 1];
  plist->base[pos] = x;
 }plist->size++;
 return true;
}

(四)按照元素大小插入

此处需要注意的是若原来的表元素是有序的则可以直接比较,若原来表无序需要先进行元素的排序在进行插入操作
在这里插入图片描述

实现过程

bool SeqListInsertByVal(SeqList *plist, ElemType x)
{              //按值插入
 assert(plist != NULL); 
 if (IsFull(plist) && !_Inc(plist, plist->capacity * 2)) {
  printf("顺序表已满,%d 不能插入!\n",x);
 }
 /* // 从前往后比较
 size_t pos = 0;
 while (pos < plist->size && x > plist->base[pos])
  pos++;
  for (size_t i = plist->size; i > pos; --i)
   plist->base[i] = plist->base[i - 1];
  plist->base[pos] = x;
 plist->size++;*/
 
 size_t end = plist->size - 1;          //从后往前比较
 while (end >=0 && x < plist->base[end]) {
  plist->base[end + 1] = plist->base[end];
  end--;
 }plist->base[end+1] = x;
 plist->size++;
 return true;
}

(五)顺序表的逆置
需要引入两个指针,一个指向表头一个指向表尾,将两个指针指向内容进行交换(注意条件的控制 : 头指针 > 尾指针)
在这里插入图片描述实现过程

void SeqListReverse(SeqList *plist)
{              //逆置
 assert(plist != NULL);
 if (plist->size == 1)
  return;
 int start = 0, end = plist->size - 1;
 while (start < end) {
  Swap(&plist->base[start], &plist->base[end]);
  start++; end--;
 }
}

(六)排序

实现过程

此处使用的是冒泡排序(双循环)

void SeqListSort(SeqList *plist)
{               //排序
 assert(plist != NULL);
 for (size_t i = 0; i < plist->size - 1; ++i) {
  for (size_t j = 0; j < plist->size - i - 1; ++j) {
   if(plist->base[j]>plist->base[j+1])
   Swap(&plist->base[j], &plist->base[j + 1]);
  }
 }
}

注意
以上是几种基本操作,相应的一系列删除操作与插入操作相对应,注意要进行表的判空判满操作

顺序表的一系列操作实现过程
顺序表的头插、尾插、按值插、按位插、查找、头删、尾删、按值删、按位删、排序、逆置等等操作

代码区

//Common.h 文件

#ifndef _COMMON_H_
#define _COMMON_H_

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
#include<memory.h>
//#include<vld.h>     //用于内存泄漏检测

#define ElemType int
void Swap(ElemType *a, ElemType *b)
{
 ElemType temp = *a;
 *a = *b;
 *b = temp;
}

#endif

//seqlist.h 文件

#ifndef _SEQLIST_H_
#define _SEQLIAT_H_
#include "Common.h"

#define SEQLIST_DEFAULT_SIZE 8
#pragma warning(disable:4996)

typedef struct SeqList
{
 ElemType *base;
 size_t capacity;  //容量
 size_t size;      //元素个数
}SeqList;

//所需要用到的函数声明
void SeqListInit(SeqList *plist);    //初始化
void SeqListDestory(SeqList *plist);
void SeqListShow(SeqList *plist);    //显示面板
void SeqListPushBack(SeqList *plist, ElemType x);  //尾插
void SeqListPushFront(SeqList *plist, ElemType x);  //头插
size_t SeqListLength(SeqList *plist);   //求长度
size_t SeqListCapacity(SeqList *plist);  //求容量
void SeqListPopBack(SeqList *plist);  //尾删
void SeqListPopFront(SeqList *plist);  //头删
void SeqListClear(SeqList *plist);    //清空
bool SeqListInsertByPos(SeqList *plist, int pos, ElemType x);   //按位置插入
bool SeqListPopByPos(SeqList *plist, int pos);   //按位置删除
void SeqListSort(SeqList *plist);  //排序
bool SeqListInsertByVal(SeqList *plist, ElemType x);//按值插入
bool SeqListEraseByVal(SeqList *plist, ElemType x); //按值删除
int SeqListFind(SeqList *plist, ElemType key);   //查找
void SeqListReverse(SeqList *plist);   //逆置



bool _Inc(SeqList *plist,size_t new_capacity)  //扩容
{
 //code  1
 /*assert(plist != NULL && new_capacity > plist->capacity);
 ElemType *new_base = (ElemType*)realloc(plist->base, sizeof(ElemType)* new_capacity);
 if (new_base == NULL) {
  return false;
 }
 plist->base = new_base;
 plist->capacity = new_capacity;
 return true;*/
 assert(plist != NULL && new_capacity > plist->capacity);
 ElemType *new_base = (ElemType*)malloc(sizeof(ElemType)*new_capacity);
 if (new_base == NULL) {
  return false;
 }
 memcpy(new_base, plist->base, sizeof(ElemType)*(plist->capacity));
 free(plist->base);              //释放旧空间
 plist->base = new_base;
 plist->capacity = new_capacity;
 return true;
}


bool IsFull(SeqList *plist)       //判满
{
 assert(plist!=NULL);
 return plist->size >= plist->capacity;
}
bool IsEmpty(SeqList *plist)     //判空
{
 assert(plist != NULL);
 return plist->size == 0;
}
void SeqListInit(SeqList *plist)   //初始化
{
 assert(plist != NULL);
 plist->capacity = SEQLIST_DEFAULT_SIZE;
 plist->base = (ElemType*)malloc(sizeof(ElemType));
 plist->size = 0;
}
void SeqListDestory(SeqList *plist)   //销毁 ---  释放空间
{
 assert(plist != NULL);
 free(plist->base);
 plist->base = NULL;
 plist->capacity = plist->size = 0;
}

void SeqListPushFront(SeqList *plist, ElemType x)
{  //头插
 assert(plist != NULL);
 if (IsFull(plist) && !_Inc(plist, plist->capacity * 2)) {
  printf("顺序表已满,头插 %d 不能插入.\n", x);
  return;
 }
 for (size_t i = plist->size; i > 0; i--) {
  plist->base[i] = plist->base[i - 1];
 }
 plist->base[0] = x;
 plist->size++;
}
void SeqListPushBack(SeqList *plist, ElemType x)
{     //尾插
 assert(plist != NULL);
 if (IsFull(plist) && !_Inc(plist,plist->capacity * 2)) {
  printf("顺序表已满,尾插 %d 不能插入.\n", x);
  return;
 }
 plist->base[plist->size++] = x;   //先放入数据,在进行数据个数加一
}
void SeqListShow(SeqList *plist)
{ //展示面板
 assert(plist != NULL);
 for (size_t i = 0; i < plist->size; ++i)
 {
  printf("%d ", plist->base[i]);
 }
 printf("\n");
}
size_t SeqListLength(SeqList *plist)   //长度
{
 assert(plist != NULL);
 return plist->size;
}
size_t SeqListCapacity(SeqList *plist)  //容量
{
 assert(plist != NULL);
 return plist->capacity;
}
void SeqListPopBack(SeqList *plist)   //尾删
{
 assert(plist != NULL);
 if (IsEmpty(plist)) {
  printf("顺序表是空的,不能进行尾部删除!\n");
 }
 plist->size--;
}
void SeqListPopFront(SeqList *plist)   //头删
{
 assert(plist != NULL);
 if (IsEmpty(plist)) {
  printf("顺序表是空的,不能进行头部删除!\n");
 }
 for(size_t i=0;i<plist->size;++i){
     plist->base[i] = plist->base[i + 1];
 plist->size--;
 }
}
void SeqListClear(SeqList *plist)     //清空
{
 assert(plist != NULL);
 plist->size = 0;
}
bool SeqListInsertByPos(SeqList *plist, int pos, ElemType x)
{              //按位置插入
 assert(plist != NULL);
 if (IsFull(plist)) {
  printf("顺序表已满,%d 不能在 %d 位置进行插入\n", x, pos);
  return false;
 }
 if (pos < 0 || pos > plist->size) {
  printf("插入的位置 %d 是非法的,%d 不能插入\n", pos, x);
  return false;
 }
 for (size_t i = plist->size; i > pos; --i) {
  plist->base[i] = plist->base[i - 1];
  plist->base[pos] = x;
 }plist->size++;
 return true;
}
bool SeqListPopByPos(SeqList *plist, int pos)
{                  //按位置删除
 assert(plist != NULL);
 if (IsEmpty(plist)) {
  printf("顺序表为空,%d 位置的数据不能被删除\n", pos);
  return false;
 }
 if (pos < 0 || pos >= plist->size) {
  printf("删除的位置 %d 是非法的,数据不能被删除\n", pos);
  return false;
 }
 for (size_t i = pos; i < plist->size; ++i) {
  plist->base[i] = plist->base[i + 1];
 plist->size--;}
 return true;
}
void SeqListSort(SeqList *plist)
{               //排序
 assert(plist != NULL);
 for (size_t i = 0; i < plist->size - 1; ++i) {
  for (size_t j = 0; j < plist->size - i - 1; ++j) {
   if(plist->base[j]>plist->base[j+1])
   Swap(&plist->base[j], &plist->base[j + 1]);
  }
 }
}
bool SeqListInsertByVal(SeqList *plist, ElemType x)
{              //按值插入
 assert(plist != NULL); 
 if (IsFull(plist) && !_Inc(plist, plist->capacity * 2)) {
  printf("顺序表已满,%d 不能插入!\n",x);
 }
 /*  //code 1 :查找插入的位置并插入
 for (size_t i = 0; i < plist->size; ++i) {
  if (plist->base[i-1] <= x && x < plist->base[i]) {
   plist->base[i + 1] = plist->base[i];
   plist->base[i] = x;
  }
 }*/
 /* //code 2: 从前往后比较
 size_t pos = 0;
 while (pos < plist->size && x > plist->base[pos])
  pos++;
  for (size_t i = plist->size; i > pos; --i)
   plist->base[i] = plist->base[i - 1];
  plist->base[pos] = x;
 plist->size++;*/
 size_t end = plist->size - 1;          //从后往前比较
 while (end >=0 && x < plist->base[end]) {
  plist->base[end + 1] = plist->base[end];
  end--;
 }plist->base[end+1] = x;
 plist->size++;
 return true;
}
int SeqListFind(SeqList *plist, ElemType x)
{             //查找数据
 assert(plist != NULL);
 int pos = 0;
 while (pos < plist->size && x != plist->base[pos]) {
  pos++;
 }
 if (pos == plist->size)      //没有找到该位置
  pos = -1;
     return pos;
}
bool SeqListEraseByVal(SeqList *plist, ElemType x)
{             //按值删除
 assert(plist != NULL);
 /*for (size_t i = 0; i < plist->size; ++i) {
  if (plist->base[i] == x) {
   for (; i < plist->size; ++i)
   plist->base[i] = plist->base[i + 1];
  plist->size--;
  }
 }*/
 int pos = SeqListFind(plist, x);
 if (pos == -1)
  return false;
 SeqListPopByPos(plist, pos);
}
void SeqListReverse(SeqList *plist)
{              //逆置
 assert(plist != NULL);
 if (plist->size == 1)
  return;
 int start = 0, end = plist->size - 1;
 while (start < end) {
  Swap(&plist->base[start], &plist->base[end]);
  start++; end--;
 }
}
#endif

//函数的调用实现过程---- TeatMain.c文件

#include "seqlist.h"

int main()
{
 SeqList list;
 SeqListInit(&list);
 ElemType item;
 int pos;
 bool flag;
 int select = 1;
 while (select) {
  printf("#########################################\n");
  printf("#   1.pushu_back        2.push.front    #\n");
  printf("#   3.show_list         0.quit_system   #\n");
  printf("#   4.pop_back          5.pop_front     #\n");
  printf("#   6.insert_pos        7.insert_val    #\n");
  printf("#   8.erase_pos         9.erase_val     #\n");
  printf("#   10.find             11.length       #\n");
  printf("#   12.capacity         13.sort         #\n");
  printf("#   14.reverse          15.clear        #\n");
  printf("##########################################\n");
  printf("please enter your select:>");
  scanf("%d", &select);
  if (select == 0)
   break;
  switch(select ) {
  case 1:  //尾插
   printf("请输入要插入的数据<以-1结束>:");
   while (scanf("%d", &item),item != -1) {
    SeqListPushBack(&list, item);
   }
   printf("尾部插入数据成功!\n");
   break;
  case 2:  //头插
   printf("请输入要插入的数据<以-1结束>:");
   while (scanf("%d", &item), item != -1) {
    SeqListPushFront(&list, item);
   }
   printf("头部插入数据成功!\n");
   break;
  case 3:  //显示面板
   SeqListShow(&list);
   break;
  case 4:  //尾删
   SeqListPopBack(&list);
   printf("尾部删除数据成功!\n");
   break;
  case 5:   //头删
   SeqListPopFront(&list);
   printf("头部删除数据成功!\n");
   break;
  case 6:   //按位置插入
   printf("请输入你想要插入的位置:>");
   scanf("%d", &pos);
   printf("请输入你想要插入的元素:>");
   scanf("%d", &item);
   flag = SeqListInsertByPos(&list, pos, item);
   if (flag) 
    printf("按位置插入成功!\n");
   else
    printf("按位置插入失败!\n");
   break;
  case 7:   //按值插入----排序
   printf("请输入你想要插入的数据:>");
   scanf("%d", &item);
   SeqListSort(&list);
   SeqListInsertByVal(&list,item);
   printf("按值插入成功!\n");
   break;
  case 8:   //按位置删除
      printf("请输入你想要删除的位置:>");
   scanf("%d", &pos);
   SeqListPopByPos(&list, pos);
   printf("按位置删除成功!\n");
   break;
  case 9:   //按值删除
   printf("请输入你想要删除的数据:>");
   scanf("%d", &item);
   SeqListEraseByVal(&list, item);
   printf("按值删除成功!\n");
   break;
  case 10:   //查找
   printf("请输入你要查找的数据:>");
   scanf("%d", &item);
   pos = SeqListFind(&list, item);
   if (pos == -1)
    printf("数据查找失败\n");
   else
    printf("数据查找成功\n");
   break; 
  case 11:   //求长度
   printf("SeqList  Length:%d\n", SeqListLength(&list));
   break;
  case 12:   //求容量
   printf("SeqList  Capacity:%d\n", SeqListCapacity(&list));
   break;
  case 13:   //排序
   SeqListSort(&list);
   printf("顺序表排序成功!\n");
   break;
  case 14:   //逆置
   SeqListReverse(&list);
   printf("顺序表逆置成功!\n");
   break;
  case 15:   //清空
   SeqListClear(&list);
   printf("顺序表清空成功!\n");
   break;
  default:
   printf("命令出错,请重新输入:>\n");
   break;
  }
  system("pause");
  system("cls");
 }
 SeqListDestory(&list);
 return 0;
}

面板展示:
在这里插入图片描述
在每一次选择之后会有一个简单的提示信息并会在下一次选择操作时进行清屏操作。

要注意传参时 &,*,以及单独的传名称的区别

(说明:内容为原创,包含个人理解方式,文件名可以自定义,若有疑问可以留言哦~)

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值