[C语言]数据结构之顺序表

简介

本文将实现顺序表的基础接口功能:
1.初始化/销毁
2.增删查改
头文件.h

#pragma once
// Sequence List

#include <stddef.h>//size_t的头文件(头文件用什么在哪写什么,不需要一通都写)

typedef int SLDataType;

struct SeqList {
	SLDataType *array; // 指针,指向存放数据的空间,真正的空间在堆上
	int capacity;  // 顺序表整体的容量
	int size;   // 顺序表中真正有效的个数
	// 初始值为 0,同时也表示下一个有效位置的下标
};

typedef struct SeqList SeqList;

// 封装的接口
// 初始化/销毁
//为什么用指针,是站在用户的角度上来写的,考虑用户怎么用
void SeqListInit(SeqList *sl, size_t capacity);
void SeqListDestroy(SeqList *sl);

// 增删查改
// 尾插,插入在顺序表的尾部
void SeqListPushBack(SeqList *sl, SLDataType data);

// 头插,插入在顺序表的头部 ([0])
void SeqListPushFront(SeqList *sl, SLDataType data);

// 尾删,删除顺序表尾部的数据
void SeqListPopBack(SeqList *sl);

// 头删,删除顺序表头部的数据
void SeqListPopFront(SeqList *sl);

//插入从中间插,在pos所在的下标做数据插入
void SeqListInsert(SeqList *sl,size_t pos,SLDataType data);

//删除pos所在的下标数据
void SeqListErase(SeqList *sl, size_t pos);

//查找
//找从0开始的第一个,如果知道了,返回数据所在的下标
//如果没找到返回-1
int SeqListFind(SeqList *sl, SLDataType data);

//删除第一个遇到的data
void SeqListRemove(SeqList *sl, SLDataType data);

//删除遇到的所有的data
void SeqListRemoveAll(SeqList *sl, SLDataType data);

//修改pos 所在的下标
void SeqListModify(SeqList *sl, size_t pos, SLDataType data);

//冒泡排序
void SeqListBubbleSort(SeqList *sl);

//二分查找(前提是数据有序)
int SeqListBinarySearch(SeqList *sl, SLDataType data);

// 打印
void SeqListPrint(SeqList *sl);

// 内部接口
void CheckCapacity(SeqList *sl);

函数实现部分SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
#include<assert.h>
#include<stdlib.h>
#include<stdio.h>
#include<stdbool.h>

//检查是否需要扩容
void CheckCapacity(SeqList *sl)
{
	 //当size大于等于capacity时就需要扩容,等于的时候也需要
	 //不符合条件
	 if (sl->size < sl->capacity)
	 { 
	 	return;
	 }
	 //1.申请新空间
	 int newCapacity = sl->capacity * 2;
	 SLDataType *newArray = (SLDataType *)malloc(sizeof(SLDataType)* newCapacity);
	 assert(newArray);
	 //2.搬家
	 for (int i = 0; i < sl->size; i++)
	 {
	 	 newArray[i] = sl->array[i];
	 }
	 //3.释放老的(释放原来的空间)
	 free(sl->array);
	 //4.保存新的
	 sl->array = newArray;
	 sl->capacity = newCapacity;
}

void SeqListInit(SeqList *sl, size_t capacity)
{
	 //传进来的指针不能为空
	 assert(sl != NULL);
	 //给容量赋值为capacity
	 //给size 赋值为0
	 //给array 开辟空间(堆上),空间大小为capacity
	 sl->size = 0;
	 sl->capacity = capacity;
	 sl->array = (SLDataType *)malloc(capacity * sizeof(SLDataType));
	 //记得做错误检查
	 assert(sl->array != NULL);
}

void SeqListDestroy(SeqList *sl)
{
	 assert(sl != NULL);
	 //推荐按进门的顺序释放,和栈的原理一样
	 free(sl->array);
	 sl->array = NULL;//防御性代码,防止下次应用时出现错误
	 sl->capacity = sl->size = 0;
}

//增
//尾插
void SeqListPushBack(SeqList *sl, SLDataType data)
{
 	CheckCapacity(sl);
 	sl->array[sl->size] = data;
 	sl->size += 1;
}

// 尾删,删除顺序表尾部的数据
void SeqListPopBack(SeqList *sl)
{
 	assert(sl != NULL);
 	assert(sl->size > 0);//还要检查这个数组有效数据的个数原本是否为0,如果为0那就没有必要再删了
 	sl->size--;
}

//头插
void SeqListPushFront(SeqList *sl, SLDataType data)
{
	 SeqListInsert(sl,0,data);//头插也可以直接调用插入函数,参数写第一个即可
#if 0
	 assert(sl != NULL);
	 //检查是否需要扩容
	 CheckCapacity(sl);
	 for (int i = sl->size; i >= 1; i--)
	 {
	  	sl->array[i] = sl->array[i - 1];
	 }
	 sl->array[0] = data;
	 sl->size++;
#endif
}

// 头删,删除顺序表头部的数据
void SeqListPopFront(SeqList *sl)
{
	 assert(sl != NULL);
	 assert(sl->size > 0);
	 for (int i = 0; i < sl->size - 1; i++)//i是数据下标,[0,size-1]
	 {
	 	 sl->array[i] = sl->array[i + 1];
	 }
	 sl->size--;
}

//中间插
void SeqListInsert(SeqList * sl, size_t pos, SLDataType data)
{
	 assert(sl);
	 CheckCapacity(sl);
	 assert(pos >= 0 && (int)pos <= sl->size);
	 //此处的i是数据下标
	 for (int i = sl->size - 1; i >= (int)pos; i--)
	 {
	 	 sl->array[i + 1] = sl->array[i];
	 }
	 sl->array[pos] = data;
 	 sl->size++;
}

//删除pos所在的下标数据
void SeqListErase(SeqList *sl, size_t pos)
{
	 assert(sl != NULL);
	 assert(sl->size > 0);
	 assert(pos >= 0 && (int)pos < sl->size);
	 for (int i = pos; i < sl->size - 1; i++)
	 {
	 	 sl->array[i] = sl->array[i + 1];
	 }
	 sl->size--;
}

//查找
int SeqListFind(SeqList *sl, SLDataType data)
{
	 for (int i = 0; i < sl->size; i++)
	 {
		  if (sl->array[i] == data)
		  {
		  	 return i;
	  	  }
	 }
	 //没找到返回-1
	 return -1;
}

//删除第一个遇到的data
void SeqListRemove(SeqList *sl, SLDataType data)
{
	 assert(sl != NULL);
	 int pos = SeqListFind(sl, data);
	 if (pos != -1)
	 {
	 	 SeqListErase(sl, pos);
	 }
}

//删除遇到的所有的data
void SeqListRemoveAll(SeqList *sl, SLDataType data)
{
	#if 0 //时间复杂度 O(n^2)
	 int pos;
	 while ((pos = SeqListFind(sl, data)) != -1)  //O(n)
	 {
	 	 SeqListErase(sl, pos); //O(n)
	 }
	#endif
	
	#if 0 //时间复杂度O(n),空间复杂度O(n)
	 SLDataType *tempArray = (SLDataType *)malloc(sizeof(SLDataType)* sl->size);
	 assert(tempArray != NULL);
	 //开辟一个新数组把不等于data的数据放进去,这样空间复杂度是O(n)
	 int j = 0;
	 for (int i = 0; i < sl->size; i++)
	 {
		  if (sl->array[i] != data)
		  {
		  	 tempArray[j++] = sl->array[i];
		  }
	 }
	 for (int k = 0; k < j; j++)
	 {
	 	 sl->array[k] = tempArray[k];
	 }
	 sl->size = j;
	#endif
	
	//定义两个变量i,j,当数据不等于data时,i和j都往后移动;
	//当数据等于data时 j 不动,i 向后移动
	//当下标为 i 的数据不等于data时 将下标为 i 的数据放在下标为j的数据处,然后 i 向后移动,j 向后移动
	//以此类推
	 //这样的时间复杂度是O(n) 空间复杂度是O(1)
	 int j = 0;
	 for (int i = 0; i < sl->size; i++)
	 {
		  if (data != sl->array[i])
		  {
		  	 sl->array[j++] = sl->array[i];
		  }
	}
	 sl->size = j;
}
	
	//修改pos 所在的下标
void SeqListModify(SeqList *sl, size_t pos, SLDataType data)
{
	 assert(sl != NULL);
	 assert(pos >= 0 && (int)pos < sl->size);
	 sl->array[pos] = data;
}

static void Swap(int *a, int *b)
{
	 int tmp = *a;
	 *a = *b;
	 *b = tmp;
}

//冒泡排序
void SeqListBubbleSort(SeqList *sl)
{
	 assert(sl != NULL);
	 for (int i = 0; i < sl->size - 1; i++)
	 {
		  bool isSort = true;
		  for (int j = 0; j <= sl->size - 2 - i; j++)
		  {
			   if (sl->array[j] > sl->array[j + 1])
			   {
				    Swap(sl->array + j, sl->array + j + 1);
				    isSort = false;
		   	   }
		  }
		  if (true == isSort)
		  {
		  	 return;
		  }
	 }
}

//二分查找(前提是数据有序)
int SeqListBinarySearch(SeqList *sl, SLDataType data)
{
	 int left = 0;
	 int right = sl->size;
	 //[left,right)
	 //left和right之间没有数的时候就不需要找了
	 while (left < right)
	 {
		  int mid = left + (right - left) / 2;
		  if (data == sl->array[mid])
		  {
		  	 return mid;
		  }
		  else if (data < sl->array[mid])
		  {
		  	 right = mid;
		  }
		  else
		  {
		  	 left = mid + 1;
	 	  }
	 }
	 return -1;
}

//打印
void SeqListPrint(SeqList *sl)
{
	 for (int i = 0; i < sl->size; i++){
	  	printf("%d ", sl->array[i]);
	 }
	 printf("\n");
}

测试部分test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
#include<assert.h>
#include<stdlib.h>

void Test1()
{
	 SeqList seqList;
	 SeqListInit(&seqList,10);//seqList的值需要发生变化,所以形参要传地址
	 assert(seqList.size == 0);//初始化的顺序表应该是空的
#if 0
	 SeqListPushBack(&seqList, 1);
	 SeqListPushBack(&seqList, 2);
	 SeqListPushBack(&seqList, 3);
	 SeqListPrint(&seqList);
	 // 1 2 3
	
	 SeqListPopBack(&seqList);
	 SeqListPopBack(&seqList);
	 SeqListPrint(&seqList);
	 // 1
	
	 SeqListPushFront(&seqList, 10);
	 SeqListPushFront(&seqList, 20);
	 SeqListPrint(&seqList);
	 // 20 10 1
	
	 SeqListPopFront(&seqList);
	 SeqListPrint(&seqList);
	 // 10 1
#endif
	
	for (int i = 0; i < 10; i++)
	 {
	 	 SeqListPushBack(&seqList,100+i);
	 }
	 SeqListPrint(&seqList);
	
	 SeqListInsert(&seqList, 5, 1005);
	 SeqListPrint(&seqList);
	
	 SeqListInsert(&seqList, 0, 1000);
	 SeqListPrint(&seqList);
	
	 SeqListInsert(&seqList, seqList.size, 2000);
	 SeqListPrint(&seqList);
	
	 SeqListErase(&seqList, 0);
	 SeqListErase(&seqList, 5);
	 SeqListPrint(&seqList);
	
	 SeqListDestroy(&seqList);
	 SeqListPrint(&seqList);
}

void Test2()//测试冒泡
{
	 SeqList seqList;
	 SeqListInit(&seqList, 10);
	 SeqListPushBack(&seqList, 6);
	 SeqListPushBack(&seqList, 3);
	 SeqListPushBack(&seqList, 2);
	 SeqListPushBack(&seqList, 5);
	 SeqListPushBack(&seqList, 1);
	 SeqListPushBack(&seqList, 7);
	
	 SeqListBubbleSort(&seqList);
	 SeqListPrint(&seqList);
	 SeqListDestroy(&seqList);
}

void Test3()//测试删除遇到的所有data
{
	 SeqList seqList;
	 SeqListInit(&seqList, 10);
	
	 SeqListPushBack(&seqList, 3);
	 SeqListPushBack(&seqList, 2);
	 SeqListPushBack(&seqList, 3);
	 SeqListPushBack(&seqList, 3);
	 SeqListPushBack(&seqList, 3);
	 SeqListPushBack(&seqList, 1);
	 SeqListPushBack(&seqList, 1);
	 SeqListPushBack(&seqList, 3);
	 SeqListPushBack(&seqList, 4);
	
	 SeqListPrint(&seqList);
	 SeqListRemoveAll(&seqList, 3);
	 SeqListPrint(&seqList);
	 SeqListDestroy(&seqList);
}

int main()
{
	 //Test1();
	 //Test2();
	 Test3();
	 system("pause");
	 return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值