408 数据结构 线性表

268 阅读7分钟

408 数据结构

线性表的基本操作
  • 这些操作的实现放在了本文章的后半部分
  • 初始化表 void InitList(seqlist* L)
  • 求表长 int Length(seqlist* L)
  • 查找某个位置上的值 ElementType Findlocate(seqlist* L, int i)
  • 按值查找 int FindValue(seqlist* L, ElementType X)
  • 销毁 void Destory(seqlist* L)
  • 判空操作 bool Empty(seqlist* L)
  • 插入 bool Insert(seqlist* L, int i, ElementType x)在表L中的第i个位置插入元素x
  • 删除 bool Delete(seqlist* L, int i, ElementType* x)在表L中的第i个位置把该元素删除,并将地址赋给e
  • 输出操作 void PrintList(seqlist* L)按前后顺序输出线性表L的所有元素值
  • 排序 void Sort(seqlist* L, int left, int right) 这里我用快排写了一个排序

写之前的头文件 结构体定义

#include <stdio.h>
#include<malloc.h>
#include <stdbool.h>

#define List_size 100
typedef int ElementType;
typedef struct {
	ElementType* data;
	int length;
	int max_size;
}seqlist;


各个基本操作的实现

初始化队列
void InitList(seqlist* L) {
	//初始化数据 元素大小乘以队列最大长度,这就是L.data指向的数据头地址。
	L->data = (ElementType*)malloc(sizeof(ElementType) * List_size);
	L->length = 0;
	L->max_size = List_size;
}

在顺序表中的第i个位置上插入指定元素e

//顺序表的第i个(1<=i<=length+1位置插入e元素
//为何判断插入位置是否合法的时候用的length+1,而移动元素的for循环中用的还是length
//因为我们日常插入队列的时候 会把第一个位置当做位置1,而计算机中则是以0 为数组下标的
//也就是说我们认为的第一位 在计算机中其实是第0位,所以在判断插入位置是自动length+1
//或者你把插入i-1 转换成计算机中的位置 也行
//length中实际上就是队列的最后一位了,它里面是不放数据的,注意程序在运行时,他运行到最后length++
//这时候最后的这个地方 他是没数据的 所以L->data[length]这个位置实际上就是这个队列的最后一位了
//然后他在倒着从后往前找
bool Insert(seqlist* L, int i, ElementType x) {
	//感觉对这个理解更深了一点,初始化时length=0 i插入到第一位时,length+1是1 他还是在这个范围内的
	if (i<1 || i>L->length + 1)
		return false;
	//大于最大长度了 也是报错
	if (L->length > List_size)
		return false;
	//从length=0开始推 j=0 i=1 j>=i条件不满足 跳出循环 顺序表中L->data[i-1] 也就是0号位上放上数据了
	// ok 成了。
	for (int j = L->length; j >= i; j--)
		L->data[j] = L->data[j - 1];
	//
	L->data[i - 1] = x;
	L->length++;
	return true;
}

删除操作 删除表L中的第i个位置上的元素,并用x返回删除元素的值

bool Delete(seqlist* L, int i, ElementType* x) {
	//插入时候可以多一个 删除就不行了 比如你说这个顺序表长10 他占用了0-9 位 一共十个 你删除这个日常的第十位
	//是不是实际上就是删除这个第九位上的数据,所以你不能再多了 你说我删第十一个 可是一共就10个,删不了
	if (i<1 || i>L->length)
		return false;
	//注意这里传的是地址哦 不对这是地址吗
	//传的是个指针 *x 表示的就是变量的值 修改变量的值
	*x = L->data[i - 1];
	//j<就行了 
	for (int j = i; j < L->length; j++)
		L->data[j - 1] = L->data[j];
	L->length--;
	return true;
}

按值查找 找到了之后返回他的位置

int FindValue(seqlist* L, ElementType X) {
	for (int i = 0; i < L->length; i++)
	{
		if (L->data[i] == X)
			return i + 1;
	}
	return 0;
}

查找位置 查找后返回元素的值

ElementType Findlocate(seqlist* L, int i)
{
	//实际位置为位序减一
	return L->data[i - 1];
}

求表长

int Length(seqlist* L)
{
	return L->length;
}

判断表空不空

//判断表空不空 空的话返回真
bool Empty(seqlist* L)
{

	if (L->length == 0)
		return true;
	else
		return false;
}

销毁操作 销毁线性表

//说实在的这个我还没用过 不知道会不会有问题
void Destory(seqlist* L)
{
	free(L);
}

输出操作 按前后顺序输出线性表L的所有元素值

void PrintList(seqlist* L)
{
	for (int i = 0; i < L->length; i++)
	{
		printf("%d ", L->data[i]);
	}
	printf("\n");
}

排序操作 这个是用快排

// 给这个顺序表进行排序 快排
// 外面的函数 就用 0 L->length 就行了
void Sort(seqlist* L, int left, int right)
{
	if (left > right)
		return;
	//存放基准数
	ElementType swap = 0;
	ElementType temp=L->data[left];
	int i = left;
	//用不用 right-1 呢 马上再看吧
	int j = right;
	//
	while (i != j)
	{
		//先从右边找 右边都是比基准数大的 找到一个比基准数小的了 停下来 记录他的位序
		while (L->data[j] >= temp && i < j)
			j--;
		//然后再从左边找 找到一个大于基准数 的  记录他的位序
		while (L->data[i] <= temp && i < j)
			i++;
		// 这个时候 如果他俩还没相遇 就交换位置
		if (i < j)
		{
			swap = L->data[i];
			L->data[i] = L->data[j];
			//猪鼻的bug  用了temp 去换了
			L->data[j] = swap;
		}
		PrintList(L);
	}
	//运行完了之后
	L->data[left] = L->data[i];
	L->data[i] = temp;
	Sort(L, left, i - 1);
	Sort(L, i + 1, right);

}

这是我用来测试的主函数 里面有一些是测试的算法函数,要是不能用的话删掉那些既可以了

int main() {
	/*ElementType x ;*/
	seqlist L,X,C;
	InitList(&L);
	InitList(&X);
	InitList(&C);


	//为什么啊 还是指针不熟悉我感觉

	Insert(&L, 1, 10);
	Insert(&L, 1, 9);
	Insert(&L, 1, 8);
	Insert(&L, 1, 7);
	Insert(&L, 1, 100);
	Insert(&L, 1, 20);
	Insert(&L, 1, 17);
	Insert(&L, 1, 19);
	PrintList(&L);
	printf("找出最小值:\n");
	int min=Delete_min(&L);
	printf("min是%d\n", min);
	PrintList(&L);
	printf("左移4位\n");
	/*LeftMove(&L, &C, 4);*/
	LeftShift(&L, 4);
	PrintList(&L);

	printf("删除10-100 内的数字\n");
	Delete_xy(&L, 10, 100);
	PrintList(&L);

	Insert(&X, 1, 8);
	Insert(&X, 1, 44);
	Insert(&X, 1, 76);
	Insert(&X, 1, 200);
	Insert(&X, 1, 123);
	Insert(&X, 1, 5);
	Insert(&X, 1, 11);
	Insert(&X, 1,888);
	printf("另一个队列\n");
	PrintList(&X);
	Sort(&X,0,X.length-1);
	PrintList(&X);


	printf("排序前\n");

	PrintList(&L);
	//printf("删除的这个数是 %d\n",x);
	/*printf("%d\n",Findlocate(&L, 2));*/
	Moveodd(&L);
	printf("排序后\n");
	PrintList(&L);
	Reverse(&L);
	PrintList(&L);
	printf("快排开始\n");
	Sort(&L, 0, L.length-1);
	printf("快排结束\n");
	PrintList(&L);
	printf("-----------------------------------------\n");
	Merge(&L, &X, &C);
	PrintList(&L);
	PrintList(&X);
	PrintList(&C);


	//Insert(L, 2, 20);
	//PrintList(L);
	//Insert(L, 1, 8);
	//PrintList(L);
	//Insert(L, 1, 9);
	//PrintList(L);
	//Insert(L, 1, 7);
	//PrintList(L);
	//Delete(L, 1, x);
	//PrintList(L);
	//PrintList(L);
	//
	return 0;
}


后面的便是在写这些代码中遇到的一些知识 作为补充放到了这里

引用这个文件来使用malloc函数

#include<malloc.h>

malloc()函数其实就在内存中找一片指定大小的空间,然后将这个空间的首地址范围给一个指针变量,这里的指针变量可以是一个单独的指针,也可以是一个数组的首地址,这要看malloc()函数中参数size的具体内容。

函数原型

void *malloc(int size);

  说明:malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。

malloc 必须要由我们计算字节数 并且强制转换成实际类型的指针。

引用这个头文件来使用bool类型

#include <stdbool.h>

更重要的指针

我在写代码的时候发现指针操作老是错,打算回去再学一下指针了。

对这个结构体操作的指针到底该怎么使用啊

输出内存地址的格式控制符为 %p 地址采用十六进制的数字显示。

通过结构体指针可以使用结构体成员,一般形式为:

  (*pointer).memberName

或者:

  pointer->memberName

第一种写法中,圆点.的优先级高于*,(pointer)两边的括号不能少。如果去掉括号写作pointer.memberName,那么就等效于*(pointer.memberName),这样意义就完全不对了。

第二种写法中,->是一个新的运算符,习惯称它为“箭头”,有了它,可以通过结构体指针直接使用结构体成员;这也是->在C语言中的唯一用途。

上面的两种写法是等效的,程序员通常采用后面的写法,这样更加直观。


写排序的时候 把这个快排整明白了

为了写那个两个有序表 合并为一个新的有序表

我得先解决那个有序表的问题 就把这个快速排序给整明白了。

void Sort(seqlist* L, int left, int right)
{
	if (left > right)
		return;
	//存放基准数
	ElementType swap = 0;
	ElementType temp=L->data[left];
	int i = left;
	//用不用 right-1 呢 马上再看吧
	int j = right;
	//
	while (i != j)
	{
		//先从右边找 右边都是比基准数大的 找到一个比基准数小的了 停下来 记录他的位序
		while (L->data[j] >= temp && i < j)
			j--;
		//然后再从左边找 找到一个大于基准数 的  记录他的位序
		while (L->data[i] <= temp && i < j)
			i++;
		// 这个时候 如果他俩还没相遇 就交换位置
		if (i < j)
		{
			swap = L->data[i];
			L->data[i] = L->data[j];
			//猪鼻的bug  用了temp 去换了
			L->data[j] = swap;
		}
		PrintList(L);
	}
	//运行完了之后
	L->data[left] = L->data[i];
	L->data[i] = temp;
	Sort(L, left, i - 1);
	Sort(L, i + 1, right);

}