数据结构之线性表及C语言实现

线性表

定义

线性表是具有相同特性数据类型的n个数据元素的有限序列。其中n为表长,n=0为空表。

结构

开始结点 -a1- 前驱结点 - a2-后继结点 - an-终端结点

特点

  • 表中元素的个数有限

  • 表中元素具有逻辑上的顺序性,表中元素有其先后次序
  • 表中元素都是数据元素,每个元素都是单个元素
  • 每个元素占有相同大小的存储空间 

注意

线性表是一种逻辑结构,表示元素之间的一对一关系 

总结

  • 线性表中地元素的类型可以为简单类型(int char float...),也可以是复杂类型(例如:姓名、班级、电话号码) 
  • 许多实际应用问题所设计的基本操作有很大相似性,不应该为每个具体应用单独编写一个程序。
  • 从具体应用中抽象出共性的逻辑结构和基本操作(抽象数据类型),然后实现其存储结构和基本操作。

        例如:存放学生的学号,姓名,成绩

typedef struct {
	char num[8]; //数据域
	char  name[8]; //数据域
	int score; //数据域

}ElemType;

typedef struct {
	ElemType data;
	int length
}List;

顺序表

定义

线性表的顺序存储又称顺序表

用一组地址连续的存储单元依次存储线性表的数据元素

特点

  1. 利用数据元素的存储位置表示线性表中相邻数据元素之间的前后关系,即线性表的逻辑结构与存储结构一致(在顺序表中,逻辑相邻的两个元素存储位置上也相邻)
  2. 在访问线性表时,可以快速地计算出任何一个数据元素地存储地址,因此可以粗略地认为,访问每个元素所花地时间相等。(这种存取元素地方法被称为随机存取法)

顺序表的顺序存储表示

由于顺序表(元素)地址连续,依次存取,随机存取,类型相同,与数组概念一样,我们用一维数组表示顺序表

注意:数组长度不可动态定义,但线性长度不可动态定义。解决方法,定义一个表长的变量。

 一维数组空间分配

静态分配:数组大小和空间已经固定,一旦空间占满,在加入新的数据会产生溢出,程序会崩溃

动态分配:一旦数据空间占满,就另外开辟一块空间更大的存储空间,用以替换原来的空间 

动态分配概念如下:

 

 int *q;

q=(int *)malloc(sizeof(int)*MAXSIZE)

定义了一个地址,将改地址附上空间,便可以存储内容

 顺序表优缺点

优点

  • 存储密度大(结点本身所占存储量/结点结构所占存储量、与链表对比)
  • 可随机存取表中任一元素

缺点

  • 在插入、删除某一元素时,需要移动大量元素
  • 浪费存储空间
  • 属于静态存储形式,数据元素的个数不能自由扩充

顺序表重要的操作

 ListInsert()//在线性表中第i个位置插入新元素  **********重点操作

void ListInsert(List *L){
	int i;
	ElemType x;
	printf_s("请输入插入的位置\n");
	scanf_s("%d", &i);
	printf_s("请输入插入的值\n");
	scanf_s("%d", &x);
	//判断表是否满了
	if (L->length == MAXSIZE) {
		printf_s("表满");
		exit(1);
	}
	//判断插入的位置是否合法
	if (i<1 || i>L->length+1) {
		printf_s("该表不存在");
		exit(1);
	}
	//将插入位置的值及后面的值全部往后移动一位
	for (int j = L->length; j >= i; j--) {
		L->a[j] = L->a[j - 1];
	}
	L->length++;
	L->a[i - 1] = x;
}

思路:

  1. 判断表是否满了(无法插入)
  2. 判断插入位置,是否合法(注意:插入的位置,可以是最前面,也可以值最后面,故可插入的位置应该 ‘length+1’)
  3. 全部符合条件,将插入的位置的值及后面的值全部往后移动一位,从尾部执行判断

缺点:需要移动大量元素

ListDelete() //删除线性表L中第i个元素    ******重点操作

void ListDelete(List *L){
	int i;
	printf_s("请输入要删除的位置\n");
	scanf_s("%d", &i);
    //判断位置是否合法
	if (i<1 || i>L->length) {
		printf_s("该位置不合法\n");
		exit(1);
	}
    //符合条件,将插入位置后面的元素全部往前移动一个位置,从表尾开始判断
	for (int j = L->length; j > i; j--) {
		L->a[j - 2] = L->a[j - 1];
	}
    //表长减1
	L->length--;
}

第二步可以或

for (int j = i; j < L->length; j++) {
		L->a[j - 1] = L->a[j];
	}

思路

  • 判断插入位置是否合法
  • 全部符合条件,将删除的元素位置后的元素全部往前移动一个位置,length-1;

缺点:需要移动大量元素

LocateElem()//查找第一个相同元素的位置

void LocateElem(List L) {
	ElemType x;
	int i=1;
	printf_s("请输入你要查找位置的值\n");
	scanf_s("%d", &x);
	for (i ; L.length >= i; i++) {
		if(L.a[i-1] == x)
		printf_s("该位置是%d", i);

	}

}

 或判断为:

	while (L.length >= i && L.a[i - 1] != x)
		i++;
	printf_s("该位置是%d", i);

思路:

  • 需要一个一个比较值是否相等,从链表头开始
  • 如果值相当跳出循序

 void InitLIsit()//初始化表

void InitList(List *L) {
	L->length = 0;
}

 思路:

将表长置于0,即置空表

void IsEmpty //判断线性表是否为空

void IsEmpty(List L) {
	if (L.length == 0)
		printf_s("该表为空");
	else
		printf_s("该表非空");
}

void DestroyList()与void ClearList()

//删除线性表,删地址
void DestroyList(List *L) {
	if (L->length)
		free(L);
}
//清空线线性表,留地址
void ClearList(List *L) {
	L->length == 0;
}

思路:

销毁线性表:销毁改该线性表的地址,不能在存放任何东西

清空线性表:将表长清零,即内容清零,地址留下

类似一个把杯子摔坏,一个倒掉里面的水

void ListLength()//求该表的表长

void ListLength(List L) {
	int x;
	x = L.length;
	printf_s("该表长为%d");
}

void GetElem() //获取第i个元素的值

void GetElem(List L) {
	int i;
	ElemType x;
	printf_s("请输入要查找的位置");
	scanf_s("%d", &i);
	if (i<1 && i>L.length) {
		printf_s("该值不合法");
		exit(1);
	}
	else
		x = L.a[i - 1];
	printf_s("该位置上的值是%d", x);

}

思路:

判断查找的值是否合法

优点:

随时存取

输入输出void printList () 和 void CreateList()//方便代码测试

//输出表
void printList(List L) {
	int i;
	for (i = 0; i < L.length; i++) {
		printf_s("%5d", L.a[i]);
	}
	printf_s("\n");
}

//创建表
void CreateList(List *L) {
	ElemType x;
	printf_s("请输入一组数据以'0'为结束符\n");
	scanf_s("%d", &x);
	while(x){
		L->a[L->length++] = x;
		scanf_s("%d", &x);
	}
	
}

以下是全部代码:

#include<stdio.h>
#include<stdlib.h>
#define  MAXSIZE 5
typedef int ElemType;

typedef struct {
	ElemType a[MAXSIZE];
	int length;
}List;
//插入元素
void ListInsert(List *L){
	int i;
	ElemType x;
	printf_s("请输入插入的位置\n");
	scanf_s("%d", &i);
	printf_s("请输入插入的值\n");
	scanf_s("%d", &x);
	//判断表是否满了
	if (L->length == MAXSIZE) {
		printf_s("表满");
		exit(1);
	}
	//判断插入的位置是否合法
	if (i<1 || i>L->length+1) {
		printf_s("该表不存在");
		exit(1);
	}
	//将插入位置的值及后面的值全部往后移动一位
	for (int j = L->length; j >= i; j--) {
		L->a[j] = L->a[j - 1];
	}
	L->length++;
	L->a[i - 1] = x;
}
//删除位置的元素
void ListDelete(List *L){
	int i;
	printf_s("请输入要删除的位置\n");
	scanf_s("%d", &i);
	if (i<1 || i>L->length) {
		printf_s("该位置不合法\n");
		exit(1);
	}
	for (int j = L->length; j > i; j--) {
		L->a[j - 2] = L->a[j - 1];
	}
	L->length--;
	
}
//输出
void printList(List L) {
	int i;
	for (i = 0; i < L.length; i++) {
		printf_s("%5d", L.a[i]);
	}
	printf_s("\n");
}
//初始化
void InitList(List *L) {
	L->length = 0;
}
//创建表
void CreateList(List *L) {
	ElemType x;
	printf_s("请输入一组数据以'0'为结束符\n");
	scanf_s("%d", &x);
	while(x){
		L->a[L->length++] = x;
		scanf_s("%d", &x);
	}
	
}
//判断表是否为空
void IsEmpty(List L) {
	if (L.length == 0)
		printf_s("该表为空");
	else
		printf_s("该表非空");
}
//按值查找位置
void LocateElem(List L) {
	ElemType x;
	int i=1;
	printf_s("请输入你要查找位置的值\n");
	scanf_s("%d", &x);
	while (L.length >= i && L.a[i - 1] != x)
		i++;
	printf_s("该位置是%d", i);

}
//删除线性表,删地址
void DestroyList(List *L) {
	if (L->length)
		free(L);
}
//清空线线性表,留地址
void ClearList(List *L) {
	L->length == 0;
}
//获取表长
void ListLength(List L) {
	int x;
	x = L.length;
	printf_s("该表长为%d");
}
//获取第i个元素位置上的值
void GetElem(List L) {
	int i;
	ElemType x;
	printf_s("请输入要查找的位置");
	scanf_s("%d", &i);
	if (i<1 && i>L.length) {
		printf_s("该值不合法");
		exit(1);
	}
	else
		x = L.a[i - 1];
	printf_s("该位置上的值是%d", x);

}

main() {
	List L;
	InitList(&L);
	CreateList(&L);
	printList(L);

}

猜你喜欢

转载自blog.csdn.net/maojiaoliang/article/details/124354140