一、线性表的概念
线性表是包含若干数据元素的一个线性序列 记为: L=(a0, ...... ai-1, ai, ai+1 ...... an-1)
L为表名,ai (0≤i≤n-1)为数据元素; n为表长,n>0 时,线性表L为非空表,否则为空表。
线性表L可用二元组形式描述:
L= (D,R)
即线性表L包含数据元素集合D和关系集合R
D={ai | ai∈datatype ,i=0,1,2, ∙∙∙∙∙∙∙∙∙n-1 ,n≥0}
R={<ai , ai+1> | ai , ai+1∈D, 0≤i≤n-2}
- 关系符<ai, ai+1>在这里称为有序对
- 表示任意相邻的两个元素之间的一种先后次序关系
- ai是ai+1的直接前驱, ai+1是ai的直接后继
设有一个顺序表L={1,2,3,4,5,6}; 他们的关系如图:
使用二元组描述L=(D,R),则
D={1 , 2 , 3 , 4 , 5 , 6}(n=6)
R={<1,2> , <2,3> , <3,4> , <4,5> , <5,6>}
线性表的特征:
- 对非空表,a0是表头,无前驱;
- an-1是表尾,无后继;
- 其它的每个元素ai有且仅有一个直接前驱ai-1和一个直接后继ai+1。
二、顺序存储的结构
若将线性表L=(a0,a1, ……,an-1)中的各元素依次存储于计算机一片连续的存储空间。
设Loc(ai)为ai的地址,Loc(a0)=b,每个元素占d个单元 则:Loc(ai)=b+i*d
顺序存储结构的特点:
- 逻辑上相邻的元素 ai, ai+1,其存储位置也是相邻的
- 对数据元素ai的存取为随机存取或按地址存取 存储密度高
- 存储密度D=(数据结构中元素所占存储空间)/(整个数据结构所占空间)
- 不足: 对表的插入和删除等运算的时间复杂度较差。
在C语言中,可借助于一维数组类型来描述线性表的顺序存储结构
#define N 100
typedef int data_t;
typedef struct
{ data_t data[N]; //表的存储空间
int last;
} sqlist, *sqlink;
三、顺序表的实现
1.创建
sqlink list_create() {
//malloc
sqlink L;
L =(sqlink)malloc(sizeof(sqlist));//L接受malloc的起始地址,
if (L == NULL) {
printf("list malloc failed\n");
return L;
}
//initialize
memset(L, 0, sizeof(sqlist));//初始化顺序表,以0填充,L为填充的起始地址
L->last = -1;//last表示最后一个有效元素的下标,-1表示没有值
//return
return L;
}
2.清空
/*
* @ret 0-success -1-failed
* */
int list_clear(sqlink L) {
if (L == NULL)
return -1;
memset(L, 0, sizeof(sqlist));
L->last = -1;
return 0;
}
3.是否为空
/*
* list_empty: Is list empty?
* para L: list
* @ret 1--empty 0--not empty
* */
int list_empty(sqlink L) {
if (L->last == -1) //最后一个元素下标为-1则为空
return 1;
else
return 0;
}
4.顺序表长度
int list_length(sqlink L) {
if (L == NULL)
return -1;
return (L->last+1);
}
5.插入
int list_insert(sqlink L, data_t value, int pos) {
int i;
//full
if (L->last == N-1) {
printf("list is full\n");
return -1;
}
//check para 0<=pos<=Last+1 位置参数取值范围[0, last+1]
if (pos < 0 || pos > L->last+1) {
printf("Pos is invalid\n");
return -1;
}
//move
for (i = L->last; i >= pos; i--) {//从后往前,元素依次后移
L->data[i+1] = L->data[i];
}
//update value last
L->data[pos] = value;
L->last++;
return 0;
}
6.打印
int list_show(sqlink L) {
int i;
if (L == NULL)
return -1;
if (L->last == -1)
printf("list is empty\n");
for (i = 0; i <= L->last; i++) {
printf("%d ", L->data[i]);
}
puts("");//换行
return 0;
}
7.删除
将表中第i个元素ai从表中删除,即实现DeleteSqlist(L, i)。
算法思路: 若参数i满足:0≤i≤L->last, 将表中L->data[i+1]∽L->data[L->last] 部分顺序向上移动一个位置,覆盖L->data[i]
int list_delete(sqlink L, int pos) {
int i;
if (L->last == -1) {
printf("list is empty\n");
return -1;
}
//pos [0, last]
if (pos < 0 || pos > L->last) {
printf("delete pos is invalid\n");
return -1;
}
//move [pos+1, last]
for (i = pos+1; i <= L->last; i++) {
L->data[i-1] = L->data[i];//后一个元素直接覆盖前一个元素
}
//update
L->last--;//last更新
return 0;
}
8.合并
设线性表La=(a0a1, ……,am-1), Lb= (b0b1, ……,bn-1),求La∪Lb =>La。
算法思路:依次取表Lb中的bi(i=0,1,……,n-1),若bi不属于La,则将其插入表La中。
int list_merge(sqlink L1, sqlink L2) {
int i = 0;
int ret;
while (i <= L2->last){
ret = list_locate(L1, L2->data[i]);//判断L1中是否含有L2的值,没有返回-1
if (ret == -1) {
if (list_insert(L1, L2->data[i], L1->last+1) == -1)
return -1;
}
i++;
}
return 0;
}
9.定位
int list_locate(sqlink L,data_t value){
int i;
for(i = 0; i <= L->last; i++){
if(L ->data[i] == value)
return i;
}
return -1;
}
10.删除重复元素
设计清除线性表L=(a0,a1,---,ai,-------,an-1)中重复元素的算法。
算法思路:对当前表L中的每个ai(0≤i≤n-2),依次与aj(i+1≤j≤n-1) 比较,若与ai相等,则删除之。
int list_purge(sqlink L) {
int i;
int j;
if (L->last == 0)
return 0;
i = 1;
while (i <= L->last) {
j = i-1;
while (j >= 0) {
if (L->data[i] == L->data[j]) {
list_delete(L, i);
break;
} else {
j--;
}
}
if ( j < 0) {
i++;
}
}
return 0;
}
四、代码
头文件
/*
typedef int data_t;
#define N 128
struct sqlist_t {
data_t data[N];
int last;
};
typedef struct sqlist_t sqlist;//sqlist L; struct sqlist_t L;
typedef struct sqlist_t * sqlink;// struct sqlist_t * p; sqlink p;
*/
typedef int data_t;
#define N 128
typedef struct {
data_t data[N];
int last;
}sqlist, *sqlink;
sqlink list_create();
int list_clear(sqlink L);
int list_delete(sqlink L);
int list_empty(sqlink L);
int list_length(sqlink L);
int list_locate(sqlink L, data_t value);
int list_insert(sqlink L, data_t value, int pos);
int list_show(sqlink L);
源程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlist.h"
sqlink list_create() {
//malloc
sqlink L;
L =(sqlink)malloc(sizeof(sqlist));
if (L == NULL) {
printf("list malloc failed\n");
return L;
}
//initialize
memset(L, 0, sizeof(sqlist));
L->last = -1;
//return
return L;
}
/*
* @ret 0-success -1-failed
* */
int list_clear(sqlink L) {
if (L == NULL)
return -1;
memset(L, 0, sizeof(sqlist));
L->last = -1;
return 0;
}
int list_free(sqlink L){
if (L == NULL)
return -1;
free(L);
L = NULL;
return 0;
}
/*
* list_empty: Is list empty?
* para L: list
* @ret 1--empty 0--not empty
* */
int list_empty(sqlink L) {
if (L->last == -1)
return 1;
else
return 0;
}
int list_length(sqlink L) {
if (L == NULL)
return -1;
return (L->last+1);
}
/*
* @ret -1--not exist pos
* */
int list_locate(sqlink L, data_t value) {
int i ;
for (i = 0; i <= L->last; i++) {
if (L->data[i] == value)
return i;
}
return -1;
}
int list_insert(sqlink L, data_t value, int pos) {
int i;
//full
if (L->last == N-1) {
printf("list is full\n");
return -1;
}
//check para 0<=pos<=Last+1 [0, last+1]
if (pos < 0 || pos > L->last+1) {
printf("Pos is invalid\n");
return -1;
}
//move
for (i = L->last; i >= pos; i--) {
L->data[i+1] = L->data[i];
}
//update value last
L->data[pos] = value;
L->last++;
return 0;
}
int list_show(sqlink L) {
int i;
if (L == NULL)
return -1;
if (L->last == -1)
printf("list is empty\n");
for (i = 0; i <= L->last; i++) {
printf("%d ", L->data[i]);
}
puts("");
return 0;
}
int list_delete(sqlink L, int pos) {
int i;
if (L->last == -1) {
printf("list is empty\n");
return -1;
}
//pos [0, last]
if (pos < 0 || pos > L->last) {
printf("delete pos is invalid\n");
return -1;
}
//move [pos+1, last]
for (i = pos+1; i <= L->last; i++) {
L->data[i-1] = L->data[i];
}
//update
L->last--;
return 0;
}
int list_merge(sqlink L1, sqlink L2) {
int i = 0;
int ret;
while (i <= L2->last){
ret = list_locate(L1, L2->data[i]);
if (ret == -1) {
if (list_insert(L1, L2->data[i], L1->last+1) == -1)
return -1;
}
i++;
}
return 0;
}
int list_purge(sqlink L) {
int i;
int j;
if (L->last == 0)
return 0;
i = 1;
while (i <= L->last) {
j = i-1;
while (j >= 0) {
if (L->data[i] == L->data[j]) {
list_delete(L, i);
break;
} else {
j--;
}
}
if ( j < 0) {
i++;
}
}
return 0;
}
测试文件
#include <stdio.h>
#include "sqlist.h"
void test_insert();
void test_delete();
void test_merge();
void test_purge();
int main(int argc, const char *argv[])
{
//test_insert();
//test_delete();
//test_merge();
test_purge();
return 0;
}
void test_insert() {
sqlink L;
L = list_create();
if (L == NULL)
return;
list_insert(L, 10, 0);
list_insert(L, 20, 0);
list_insert(L, 30, 0);
list_insert(L, 40, 0);
list_insert(L, 50, 0);
list_insert(L, 60, 0);
list_show(L);
//list_insert(L, 100, list_length(L));
list_insert(L, 100, -1000);
list_show(L);
list_free(L);
}
void test_delete() {
sqlink L;
L = list_create();
if (L == NULL)
return;
list_insert(L, 10, 0);
list_insert(L, 20, 0);
list_insert(L, 30, 0);
list_insert(L, 40, 0);
list_insert(L, 50, 0);
list_insert(L, 60, 0);
list_show(L);
list_delete(L, 9);
list_show(L);
list_free(L);
}
void test_merge() {
sqlink L1, L2;
L1 = list_create();
if (L1 == NULL)
return;
L2 = list_create();
if (L2 == NULL)
return;
list_insert(L1, 10, 0);
list_insert(L1, 20, 0);
list_insert(L1, 30, 0);
list_insert(L1, 40, 0);
list_insert(L2, 50, 0);
list_insert(L2, 20, 0);
list_insert(L2, 90, 0);
list_insert(L2, 40, 0);
list_show(L1);
list_show(L2);
printf("********************\n");
list_merge(L1, L2);
list_show(L1);
list_show(L2);
}
void test_purge() {
sqlink L;
L = list_create();
if (L == NULL)
return;
list_insert(L, 10, 0);
list_insert(L, 10, 0);
list_insert(L, 10, 0);
list_insert(L, 10, 0);
list_insert(L, 10, 0);
list_insert(L, 10, 0);
list_show(L);
list_purge(L);
list_show(L);
list_free(L);
}
五、作业
1、根据自己的理解,画一幅图来表示一个空的顺序表;
2、搭建顺序表的框架代码(类似于课程中老师写的);
3、写一个函数,功能为去除线性表中的重复元素(例如:1、1、1、2、3、4、4、5、6,去重之后为1、2、3、4、5、6);
4、写一个函数,功能为线性表的合并La = La U Lb(例如:La:1、2、3、4;Lb:4、5、6、7;合并之后La:1、2、3、4,、5、6、7;Lb:4、5、6、7);