数据结构基础知识(线性表1)

二.线性表

定义:线性表是由n个属于同一个对象的数据元素a1,a2…an组成的有限序列。当1<i<n时,ai的直接前驱元素为ai-1,ai的 直接后继元素为ai+1,除表中第一元素没有直接前驱和最后一个元素没有直接后继,其他每个数据都有一个直接前驱和直接后继。n为元素的个数也就是线性表的长度。长度为0时为空表。
对于非空线性表每个数据元素在表中都有一个确定的位置。
特点:数据元素之间存在着“一对一”的逻辑关系
线性表可以用一个标识符来命名
A=(a1,a2,a3…an)
线性表的基本操作:
1.将线性表设置为空表。
2.测试一个线性表是否为空
3.求线性表的长度
4.检索线性表中第i个数据元素
5.根据数据元素的某个数据项(通常称之为关键字)的值求该元素在线性表中的位置,即数据定位
6.在线性表的第i个位置插入一个元素,并使其线性表的长度加一
7.在线性表的第i个位置存入一个新的值
8.删除线性表中的第i个数据元素,并使其线性表长度减一
9.删除线性表中重复出现的元素
10.对一个线性表的数据元素按照某个数据项值的大小做升序或者降序排序
11.复制一个线性表,即产生一个与已有线性表相同的新的线性表
12.按照一定的原则,将两个或者两个以上的线性表合并为一个线性表
13.按照一定的原则,将一个线性表分解为两个或者多个线性表
·线性表的存储结构
顺序存储结构:
用一组地址连续的存储单元来依次存储线性表的数据元素。称为线性表的顺序存储结构,并称此时的线性表为顺序表。
假设线性表每个数据元素具有相同的属性,那么线性表中第i+1个数据元素ai+1的存储位置与第i个数据元素ai的存储位置之间存在如下关系
LOC(ai+1)=LOC(ai)+k
符号LOC是寻根地址,表示数据元素的存储位置,即数据元素占用的k个连续存储单元的第一个单元的地址。线性表中第i个数据元素的ai的存储位置为:
LOC(ai)=LOC(a1)+(i-1)*k
常见的几种操作的实现:
1.在长度为n的线性表A的第i个位置插入一个新数据元素
满足插入条件,具体插入过程分为3步:
a.将线性表的第i个数据元素到第n个数据元素之间的所有元素依次向后移动一个位置(共移动n-i+1个)
b.将新的数据元素item插入到线性表的第i个位置上
c.修改线性表的长度为n+1
在线性表中插入一个数据元素时需要移动其他元素的平均次数为n/2,算法时间复杂度为O(n)
2.删除长度为n的线性表A的第i个数据元素
如果满足删除条件,具体删除过程可以分为两步:
a.将表中的第i+1个数据元素至第n个数据元素依次向前移动一个位置
b.修改线性表的长度为n-1
在线性表中删除一个数据元素时需要移动其他元素的平均次数为(n-1)/2,算法时间复杂度为O(n)
3.确定元素item在长度为n的线性表A中的位置
依次比较item和每个元素是否相同。时间复杂度为O(n)
4.删除表中重复出现的元素
依次检查在某元素后面的元素中是否存在与之相同的元素。存在,则删除,并修改长度。算法的时间复杂度为O(n2)
5.对线性表元素进行排序
a.插入排序
b.冒泡排序
c.选择排序
d.希尔排序
e.快速排序
f.堆积排序
g.二路归并排序
h.基数排序
优点:
1.构造简单,较为直观,易理解
2.若已知每个数据元素所占用的存储单元的个数,并且知道第一个数据元素的存储位置,则表中任意一个数据元素的位置可以通过解析式来计算出来
3.对表中所有数据元素,既可以进行顺序访问,也可以进行随机访问,也就是说,可以从表中任意一个数据元素进行访问。
4.只需要存放数据元素本身,而无需其他额外的空间。
缺点:
1.需要一片地址连续的存储单元作为线性表的存储空间
2.存储空间需要事先进行,使得应该分配的内存不易估计。
3.进行插入删除操作时,操作时间效率低
例如:#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define SIZE 50//线性表的大小
//打印元素
void print() {
printf(“1.添加 \t 2.删除\n\n”);
printf(“3.元素的位置\t 3.排序\n \n”);
printf(“5.删除表中重复元素 6.退出\n\n”);
}
//进行元素的添加
void insert(int a[],int *n,int i, int item)
{
int j;
if ((*n) == SIZE || i<1 || i>(*n+1))
{
printf(“插入的位置不正确”);
system(“pause”);
return;
}
for (j = (*n) - 1; j >= i - 1; j–)
{
a[j + 1] = a[j];
}
a[i - 1] = item;
(*n)++;
}
void delect(int a[] ,int *n,int i)
{
int j;
if ((*n) == SIZE || i<1 || i>(n + 1))
{
printf(“插入的位置不正确”);
system(“pause”);
return;
}
for ( j = i; j <(
n); j++)
{
a[j - 1] = a[j];
}
(*n)–;
}
//位置查找
int local(int a[], int *n, int item)
{
int i;
for (i = 0; i < (*n); i++)
{
if (a[i] == item)
{
return i + 1;
}

}
	
	printf("查找失败!");
	system("pause");
	return -1;

}
//排序
void desc(int a[], int *n)
{
int i, j, d;
int temp;
for ( i = 0; i < (n)-1; i++)
{
d = i;
for ( j = i+1; j <(
n); j++)
{
if (a[j] < a[d])
d = j;
}
if (d != i)
{
temp = a[d];
a[d] = a[i];
a[i] = temp;
}
}
}

//删除重复元素
void purge(int a[],int *n)
{
int i = 0, j;
while (i < *n)
{
j = i + 1;
while (j < *n)
if (a[j] == a[i])
delect(a, n, j + 1);
else
j++;
i++;
}
}

void main() {
int data[SIZE];
int n,i,j,k,z;//多少个操作数
printf(“请输入多少个操作数(空格分割)\n”);
scanf("%d “,&n);
int length = n;
for ( i = 0; i < n; i++)
{
scanf(”%d",&data[i]);
}

while (true)
{
	print();
	printf("\n请输入需要的操作\n");
	scanf("%d",&j);
	switch (j)
	{
	case 1:
		printf("请输入要添加的元素\n");
		scanf("%d",&k);
		printf("前输入要添加的位置\n");
		scanf("%d",&z);
		insert(data, &n, z, k);
		break;
	case 2:
		printf("请输入要删除的元素\n");
		scanf("%d",&z);
		delect(data,&n,z);
		break;
	case 3:
		printf("请输入要查找的数:\n");
		scanf("%d",&z);
		printf("所查找的数在第%d个位置\n",local(data,&n,z));
		break;
	case 4:
		printf("从小到大排序\n");
		desc(data, &n);
		break;
	case 5:
		purge(data,&n);
		break;
	case 6:
		exit(1);
	default:
		printf("输入错误!重新输入\n");
	}
	printf("所输入的数据为:\t\n");
	for ( i = 0; i < n; i++)
	{
		printf("%d\t ",data[i]);
	}
	printf("\n");
}
system("pause");

}
线性链表的构造:
线性表的链式存储是用一组地址任意的存储单元来依次存储线性表中的各个数据元素。
每个节点分为两部分:用于存储的一个数据元素本身信息的域称为数据域,用符号data作为该域的域名;存储一个数据元素逻辑上的直接后继元素存储位置的域称为指针域,用link作为指针域的域名。
Data link
对于线性表
A=(a1,a2,a3…an)
直接用箭头连接

a1 a2 a3 a4
整个线性表由一个外指针的变量来指出,它表明线性链表的首地址(头节点)
链表中的各个链接点占用的存储空间之间不要求连续,但是每一个链结点内部占用的一系列存储单元必须连续。
如:typedef struct node{
elemType data;
Struct node *link;
}LNode,*LinkList
链表分为动态链表和静态链表
若指针变量p为指向线性链表中某个链接点的指针,则:
1.若符号p->data出现在表达式中,它表示由p所指向链接点的数据域信息(内容);否则,表示由p所指向的那个链接点的数据域。
2.若符号p->link出现在表达式中,他表示p所指的链接点的指针域信息,也就是p所指的链接点的下一个链接点的存储地址,否则,表示由p所指向的那个链接点的数据域。
线性表的基本算法:
1.建立一个线性表
建立一个线性链表的过程就是一个动态生成链接点并依次将他们连接到链表中的过程。
2.求线性表的长度
线性链表的长度被定义为链表中包含节点的个数。
3.测试线性表是否为空表
4.确定元素item在线性表中的位置
5.在非空链表的第一个链接点前插入一个数据为item的链接点
6.在非空线性链表的末尾插入一个数据信息为item的链接点
7.在线性表中由指针q指出的链接点后面插入一个数据为item的链接点
8.在线性链表中第i个链接点后面插入一个数据信息为item的链接点
9.在按值有序链表的线性表中插入一个数据为item的链接点
10.从非空线性表中删除q所指的链接点
11.销毁一个线性链表
12.删除线性表中数据值为item的所有连接
13.逆转一个线性链表
14.将两个非空线性表连接成一个线性链表
15.将两个按值有序连接的非空线性链表合并为一个按值有序连接的线性链表
16.复制一个线性链表
17.利用线性链表进行数据排序

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct data {
int num;
struct data *next;
}DaTa,Data;
//建立一个线性链表
struct data
creat(int n)
{
Data p, r=NULL, list=NULL;
int z;//输入的数据
int i;
for ( i = 0; i < n; i++)
{
printf(“请输入第%d个数据:”,i+1);
scanf("%d",&z);
p = (struct data *)malloc(sizeof(DaTa));
p->num = z;
p->next = NULL;
if (list == NULL)
list = p;
else
r->next = p;
r = p;
}
return list;
}
//求该链表的长度
void length(struct data * list)
{
Data p = list;
int n = 0;
while (p != NULL)
{
n++;
p = p->next;
}
printf(“该线性表的长度为:%d \t\n”, n);
}
//判断该线性表是否为空表
void isempty(Data list)
{
if (list == NULL)
{
printf("\n该线性表为空\n");
}
else
printf("\n该线性表部位空\n");
}
//确定元素在线性表中的位置
void find(Data list,int item)
{
Data p = list;
int z = 0;
while (p != NULL && p->num != item)
{
z++;
p = p->next;
}
printf(“所查找的元素在第%d个位置(0为没有查到)\n”,z);
}
//在线性表第一个链接点插入一个数据
Data inserthead(Data list, int item)
{
Data p;
p = (struct data *)malloc(sizeof(DaTa));
p->num = item;
p->next = list;
list = p;
return list;
}
//在末尾插入一个数据
Data inserttail(Data list, int item)
{
Data p,r;
r = list;
while (r->next != NULL)
r = r->next;
p = (struct data *)malloc(sizeof(DaTa));
p->num = item;
p->next = NULL;
r->next = p;
return list;
}
//在线性表第i个数据后面插入一个节点
int insertmiddle(Data list, int i, int item)
{
Data p, q = list;
int j = 1;
while (j < i&&q != NULL)
{
q = q->next;
j++;
}
if ((j != i || q == NULL))
{
printf("\n失败\n");
return -1;
}
p = (struct data *)malloc(sizeof(DaTa));
p->num = item;
p->next = q->next;
q->next = p;
return 1;
}
//在非空链表中删除值item的链接点
void delect(Data list, int item)
{
Data p, q = list;
p = list->next;
while (p != NULL)
{
if (p->num == item)
{
q->next = p->next;
free§;
p = q->next;
}
else {
q = p;
p=p->next;
}
}
if (list->num == item)
{
q = list;
list = list->next;
free(q);

}

}
void print(struct data *a)
{
Data p = a;
printf(“输出的数据为:\n”);
while (p != NULL)
{
printf("%d\t", p->num);
p = p->next;
}
printf("\n");
}
//调用函数即可
void main()
{
int n;
Data head;
printf(“请输入存取多少个数据:\n”);
scanf("%d",&n);
head = creat(n);
length(head);
print(head);

system("pause");

}
//将矩阵逆转
Data invert(Data list)
{
Data p, q, r;
p = list;
q = NULL;
while (p != NULL)
{
r = q;
q = p;
p = p->next;
q->next = r;
}
list = q;
return list;

}
//将两个非空线性链表连接成一个线性链表
void connect(Data lista, Data listb)
{
Data p;
for (p = lista; p->next; p = p->next);
p->next = listb;
}

//.将两个按值有序连接的非空线性链表合并为一个按值有序连接的线性链表
Data merge(Data lista, Data listb)
{
Data listc, p = lista, q = listb,r;
if (lista->num <= listb->num)
{
listc = lista;
r = lista;
p = lista->next;
}
else
{
listc = listb;
r = listb;
q = listb->next;
}
while (p != NULL && q != NULL)
{
if (p->num < q->num)
{
r->next = p;
r = p;
q = q->next;
}
else
{
r->next = q;
r = q;
q = q->next;
}
}
r->next = p ? p : q;//插入剩余的链接点
return listc;
}
//复制一个线性链表
Data copy(Data lista)
{
Data listb;
if (lista == NULL)
{
return NULL;
}
else {
listb= (struct data *)malloc(sizeof(DaTa));
lista->num = lista->num;
listb->next = copy(lista->next);//运用递归
}
return listb;
}

//利用线性链表进行数据排序
void linksort(int a[], int n)
{
Data p, list = NULL;
int i;
for (i = 0; i < n; i++)
{
insert(list a[i]);
}
p = list;
i = 0;
while (p != NULL)
{
a[i++] = p->num;
p = p->next;
}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值