【数据结构初阶】(1)C语言实现线性表之顺序表


1、 顺序表实现

1.1 概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:

  • 静态顺序表:使用定长数组存储。

  • 动态顺序表:使用动态开辟的数组存储。

1.2 接口实现

  • ☀️SeqList.h
#pragma once
//防止头文件重复包含

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#define MAX_SIZE 5
typedef int SQDataType;
//静态顺序表
//typedef struct SeqList 
//{
//	SQDataType a[MAX_SIZE];
//	int size;//
//}SL;
// 
//动态顺序表
typedef struct SeqList
{
	SQDataType*a;
	int size;//
	int capacity;
}SL;

//增删改查
void SeqListInit(SL *ps);//初始化
void SeqListPrint(SL* ps);//打印
void SeqListDestroy(SL* ps);//销毁
void SeqListCheckCapacity(SL* ps);//检查容量

void SeqListPushBack(SL *ps,SQDataType x);//尾插
void SeqListPushFront(SL *ps,SQDataType x);//头插
void SeqListPopBack(SL* ps);//尾删
void SeqListPopFront(SL* ps);//头删
void SeqListInsert(SL* ps, int pos, SQDataType x);//指定位置插入
void SeqListErase(SL* ps, int pos);//指定位置删
int SeqListFind(SL* ps,SQDataType x);//查找
void SeqListModify(SL* ps,int pos,SQDataType x);//修改
  • ☀️SeqList.c
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"

//void SeqListInit(SL *ps)//静态顺序表初始化
//{
//	memset(ps->a, 0, sizeof(SQDataType)*MAX_SIZE);
//	ps->size = 0;
//}

//初始化
void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

//void SeqListPushBack(SL* ps, SQDataType x)//静态顺序表的尾插
//{
//	if (ps->size >= MAX_SIZE)
//	{
//		printf("Seqlist is Full\n");
//		return;
//	}
//	ps->a[ps->size] = x;
//	ps->size++;
//}


//销毁
void SeqListDestroy(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}


//检查容量够不够
void SeqListCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SQDataType* tem = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType));
		if (tem == NULL)
		{
			perror("realloc fail");
		}
		else
		{
			ps->a = tem;
			ps->capacity = newcapacity;
		}
	}
}


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


//尾插
void SeqListPushBack(SL* ps, SQDataType x)
{
	//满了就要扩容
	SeqListCheckCapacity(ps);

	ps->a[ps->size] = x;
	ps->size++;
}


//头插
void SeqListPushFront(SL* ps, SQDataType x)
{
	SeqListCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];//往后挪
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}


//尾删
void SeqListPopBack(SL* ps)
{
	assert(ps->size > 0);
	ps->size--;
}


//头删
void SeqListPopFront(SL* ps)
{
	assert(ps->size > 0);

	int start = 1;
	while (start < ps->size)
	{
		ps->a[start - 1] = ps->a[start];
		start++;
	}
	ps->size--;
}


//指定位置插入
void SeqListInsert(SL* ps, int pos, SQDataType x)
{
	assert(pos < ps->size);
	SeqListCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end+1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}


//指定位置删除
void SeqListErase(SL* ps, int pos)
{
	assert(pos < ps->size);//删的位置要有值
	int start = pos + 1;
	while (start < ps->size)
	{
		ps->a[start - 1] = ps->a[start];
		start++;
	}
	ps->size--;
}


//查找
int SeqListFind(SL* ps,SQDataType x)
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}


//修改
void SeqListModify(SL* ps, int pos, SQDataType x)
{
	assert(pos < ps->size);
	ps->a[pos] = x;
}

2、测试模块

  • 🌲test.c
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"

void TestSeqList()
{
	//实现一个接口就进行测试
	SL s;
	SeqListInit(&s);
	SeqListPushBack(&s, 1);
	SeqListPushBack(&s, 2);
	SeqListPushBack(&s, 3);
	SeqListPushBack(&s, 4);
	SeqListPushBack(&s, 5);
	SeqListPushBack(&s, 6);
	SeqListPushFront(&s, 7);
	SeqListPrint(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPopBack(&s);
	SeqListPrint(&s);
	SeqListPopFront(&s);
	SeqListPrint(&s);
	SeqListInsert(&s, 0, 20);
	SeqListPrint(&s);
	SeqListErase(&s, 0);
	SeqListPrint(&s);

	SeqListDestroy(&s);
}

void menu()
{
	printf("**********************************************\n");
	printf("1. 尾插数据  2. 头插数据\n");
	printf("3. 尾删数据  4. 头删数据\n");
	printf("5. 打印数据  0. 退出\n");
	printf("**********************************************\n");
	printf("请输入你的操作选项:");
}
int main()
{
	//TestSeqList();
	SL s;
	SeqListInit(&s);
	int option = 0;
	int x = 0;
	do 
	{
		menu();
		scanf("%d", &option);
		switch (option)
		{
		case 0:
			printf("退出成功\n");
			break;
		case 1:
			printf("输入你要插入的数据,以-1结束\n");
			do
			{
				scanf("%d", &x);
				if (x != -1)
				{
					SeqListPushBack(&s, x);
				}
			} while (x != -1);
			/*system("cls");*/
			break;
		case 2:
			printf("输入你要插入的数据,以-1结束\n");
			do
			{
				scanf("%d", &x);
				if (x != -1)
				{
					SeqListPushFront(&s, x);
				}
			} while (x != -1);
			break;
		case 3:
			SeqListPopBack(&s);
			printf("删除成功\n");
			break;
		case 4:
			SeqListPopFront(&s);
			printf("删除成功\n");
			break;
		case 5:
			SeqListPrint(&s);
			break;
		default:
			printf("选择错误\n");
			break;
		}

	} while (option);

	SeqListDestroy(&s);
	return 0;
}

3、顺序表OJ题

① LeetCode:移除元素

AC示例:

int removeElement(int* nums, int numsSize, int val){
    int src = 0;
    int dest = 0;
    while (src < numsSize)
    {
        if (val == nums[src])
        {
            src++;
        }
        else
        {
            nums[dest++] = nums[src++];
        }
       
    }
    return dest;

}

② 牛客:序列中删除指定数字

在这里插入图片描述

AC代码示例:

#include <stdio.h>
#include <stdlib.h>
void Delete(int* arr,int *arrLen,int target)
{
	//双指针
    int src = 0;
    int dest = 0;
    while (src < *arrLen)
    {

        if (arr[src] == target)
        {
            src++;
        }
        else
        {
            arr[dest++] = arr[src++];
        }
       
    }
    *arrLen = dest;
}

void Print(int* arr, int arrLen)
{
    for (int i = 0; i < arrLen; ++i)
    {
        printf("%d ", arr[i]);
    }
}
void Init(int* arr, int arrLen)
{
    for (int i = 0; i < arrLen; ++i)
    {
        scanf("%d", &arr[i]);
    }
}
int main()
{
    int n = 0;
    int target = 0;
    scanf("%d", &n);
    int* arr = (int*)malloc(n * sizeof(int));
    if (NULL == arr)
    {
        return 0;
    }

    Init(arr, n);
    scanf("%d", &target);

    Delete(arr, &n, target);

    Print(arr, n);
    free(arr);
    arr = NULL;
    return 0;
}

③ LeetCode:合并两个有序数组

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int end1 = m-1;
    int end2 = n-1;
    int end = m+n-1;
    //从后往前拷贝,大的拷贝到nums1
    while (end1 >= 0 && end2 >= 0)//有一个数组走完就不进入循环
    {
        if (nums1[end1] > nums2[end2])
        {
            nums1[end--] = nums1[end1--];
        }
        else
        {
            nums1[end--] = nums2[end2--];
        }
    }
    //情况1:nums1没走完,nums2走完,不需要处理
    //情况2:nums1走完,nums2没走完,把nums2继续拷贝
    while (end2 >= 0)
    {
        nums1[end--] = nums2[end2--];
    }
}

④ 牛客:有序序列合并

#include <stdio.h>
#include <stdlib.h>
void Init(int *arr,int arrLen)
{
    for (int i = 0;i < arrLen;++i)
    {
        scanf("%d ",&arr[i]);
    }
}
void Merge(int *arr1,int n,int *arr2,int m)
{
    int end1 = n-1;
    int end2 = m-1;
    int end = m+n-1;
    while (end1 >= 0 && end2 >= 0)
    {
        if (arr1[end1] < arr2[end2])
        {
            arr1[end--] = arr2[end2--];
        }
        else
        {
            arr1[end--] = arr1[end1--];
        }
    }
    while (end2 >= 0)
    {
        arr1[end--] = arr2[end2--];
    }
}
void Print(int *arr,int arrLen)
{
    for (int i = 0;i < arrLen;++i)
    {
        printf("%d ",arr[i]);
    }
}
int main()
{
    int n = 0,m = 0;
    scanf("%d%d",&n,&m);
    int *arr1 = (int*)malloc((n+m)*sizeof(int));
    int *arr2 = (int*)malloc(m*sizeof(int));
    if (NULL == arr1 || NULL == arr2)
    {
        return 0;
    }
    Init(arr1,n);
    for (int i = n;i < m+n;++i)
    {
        arr1[i] = 0;
    }
    Init(arr2,m);
    Merge(arr1,n,arr2,m);
    Print(arr1,n+m);
    free(arr1);
    arr1 = NULL;
    free(arr2);
    arr2 = NULL;
    return 0;
}

本文到此就结束了,如果有错误,请指正。🌹

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二木 同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值