【数据结构】02-线性表(第一部分 2.1 & 2.2 线性表的顺序表示和实现)《数据结构 C语言版(严蔚敏、吴伟民)》

文章目录

  • 教材 > 第2章 线性表(2.1 和 2.2 线性表的顺序表示和实现)
    • 2.1 线性表的类型定义
    • 2.2 线性表的顺序表示和实现
  • 附一:结构图
    • 1、线性表的顺序结构图
    • 2、线性表的插入删除示意图
  • 附二:教材算法实现
    • 1、线性表结构及基本操作
    • 2、线性表扩展(有a、b两个线性表,扩展a表,把b表中有而a表中没有的插入a表)
    • 3、线性表合并(有a、b两个非递减有序线性表,将a、b归并为c表,c表扔按非递减排列)

教材 > 第2章 线性表(2.1 和 2.2 线性表的顺序表示和实现)

线性结构的特点:

在数据元素的非空有限集中,

  1. 存在唯一的一个被称作“第一个”的数据元素;
  2. 存在唯一的一个被称作“最后一个”的数据元素;
  3. 除第一个之外,集合中的每个数据元素均只有一个前驱;
  4. 出最后一个之外,集合中每个数据元素均只有一个后继;

2.1 线性表的类型定义

  • 线性表:是 n 个数据元素的有限序列;
  • 一个数据元素可以由若干个数据项组成。(常把数据元素成为记录,含有大量记录的线性表称文件)
  • 同一线性表中的元素必定具有相同特性;
  • 线性表中元素的个数 n(n>=0)定义为线性表的长度,n=0 时称为空表;
  • a.i 是第 i 个数据元素,称 i 为数据元素 a.i 在线性表中的位序;

2.2 线性表的顺序表示和实现

  • 线性表的顺序表示:用一组地址连续的存储单元依次存储线性表的数据元素;

  • 以第一个单元的存储地址作为数据元素的存储位置,称为线性表的起始位置或基地址;

  • 如果每个元素占用 l 个存储单元,第 i 个数据元素的存储位置:LOC(a.i) = LOC(a.1) + (i+1)*l ;

  • 线性表的元素在计算机内以“物理位置相邻”来表示线性表中数据元素之间的逻辑关系;

  • 通常用数组来描述数据结构中顺序存储结构;

  • 顺序存储结构的插入、删除操作时,其时间主要耗费在移动数据元素上;

  • 线性表的操作:

    • 初始化
    • 销毁
    • 清空
    • 判空
    • 计算长度
    • 取某元素
    • 判断元素存在
    • 返回元素前驱
    • 返回元素后继
    • 插入
    • 删除
    • 遍历

附一:结构图

1、线性表的顺序结构图

【数据结构】02-线性表(第一部分 2.1 & 2.2 线性表的顺序表示和实现)《数据结构 C语言版(严蔚敏、吴伟民)》_第1张图片

2、线性表的插入删除示意图

【数据结构】02-线性表(第一部分 2.1 & 2.2 线性表的顺序表示和实现)《数据结构 C语言版(严蔚敏、吴伟民)》_第2张图片

附二:教材算法实现

1、线性表结构及基本操作

使用数组实现线性表的定义和基本增、删、改、查、遍历等操作;

// 线性表顺序结构及基本操作(头文件)
// file_name: 2_1.h

#ifndef __2_1_H__
#define __2_1_H__

#include 
#include 

#define Status 	int
#define ERROR 	-1
#define OK		0

#define LIST_INIT_SIZE	100		// init size of list
#define LISTINCREMENT	10		// step of increment

typedef int ElemType;	// type of elem

typedef struct{
	ElemType *elem;		// base addr
	int length;			// current len
	int listsize;		// size of list
}SqList;

// - Compare
Status Compare(ElemType cur_e, ElemType e);

// - Visit
void Visit(ElemType e);

// - 初始化
Status InitList(SqList *l);

// - 销毁
void DestroyList(SqList *l);

// - 清空
void ClearList(SqList *l);

// - 判空
Status ListEmpty(SqList l);

// - 计算长度
int ListLength(SqList l);

// - 取某元素
Status GetElem(SqList l, int i, ElemType *e);	

// - 返回首个与给出元素满足Compare关系的位序
int LocateElem(SqList l, ElemType e, Status(Compare)(ElemType, ElemType));	

// - 返回元素前驱
Status PriorElem(SqList l, ElemType cur_e, ElemType *pre_e);

// - 返回元素后继
Status NextElem(SqList l, ElemType cur_e, ElemType *next_e);

// - 插入
Status ListInsert(SqList *l, int i, ElemType e);

// - 删除
Status ListDelete(SqList *l, int i, ElemType *e);

// - 遍历
Status ListTraverse(SqList l, void(Visit)(ElemType));	

#endif // __2_1_H__

// 线性表顺序结构及基本操作(源文件)
// file_name: 2_1.c

#include "2_1.h"

// - Compare
Status Compare(ElemType cur_e, ElemType e){
	
	if(cur_e == e){
		return OK;
	}

	return ERROR;
}

// - Visit
void Visit(ElemType e){
	printf("%d  ", e);
}

// - 初始化
Status InitList(SqList *l){
	
	l->elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
	if(!(l->elem)){
		return ERROR;
	}

	l->length = 0;
	l->listsize = LIST_INIT_SIZE;

	return OK;
}

// - 销毁
void DestroyList(SqList *l){
	free(l->elem);

	l->elem = NULL;
	l->length = 0;
	l->listsize = 0;
}

// - 清空
void ClearList(SqList *l){
	l->length = 0;
}

// - 判空
Status ListEmpty(SqList l){
	return (l.length==0) ? OK : ERROR;
}

// - 计算长度
int ListLength(SqList l){
	return l.length;
}

// - 取某元素
Status GetElem(SqList l, int i, ElemType *e){
	
	if(i<1 || i>l.length){
		return ERROR;
	}else{
		(*e) = l.elem[i-1];
	}

	return OK;
}

// - 返回首个与给出元素满足Compare关系的位序
int LocateElem(SqList l, ElemType e, Status(Compare)(ElemType, ElemType)){
	
	int i = 1;
	
	for(i=1; i<=l.length; i++){
		if(OK == Compare(l.elem[i-1], e)){
			return i;
		}
	}

	return 0;
}

// - 返回元素前驱
Status PriorElem(SqList l, ElemType cur_e, ElemType *pre_e){
	
	if(l.elem[0] != cur_e){
		int i = 1;
		for(i=1; i<l.length; i++){
			if(l.elem[i] == cur_e){
				*pre_e = l.elem[i-1];
				return OK;
			}
		}
	}

	return ERROR;
}

// - 返回元素后继
Status NextElem(SqList l, ElemType cur_e, ElemType *next_e){
	
	int i = 0;
	
	for(i=0; i<l.length-1; i++){
		if(l.elem[i] == cur_e){
			*next_e = l.elem[i+1];
			return OK;
		}
	}

	return ERROR;
}

// - 插入
Status ListInsert(SqList *l, int i, ElemType e){
	
	if(i<1 || i>l->length+1){
		return ERROR;
	}

	ElemType *new_base;

	if(l->length >= l->listsize){
		// realloc
		new_base = (ElemType *)realloc(l->elem, (l->length+LISTINCREMENT)*sizeof(ElemType));
		if(NULL == new_base){
			return ERROR;
		}

		l->elem = new_base;
		l->listsize += LISTINCREMENT;
	}

	// move
	int j;
	for(j=l->length; j>=i; j--){
		l->elem[j] = l->elem[j-1];
	}

	// insert
	l->elem[i-1] = e;
	l->length++;

	return OK;
}

// - 删除
Status ListDelete(SqList *l, int i, ElemType *e){

	if(i<1 || i>l->length){
		return ERROR;
	}

	// get value
	*e = l->elem[i-1];

	// move
	int j;
	for(j=i; j<l->length; j++){
		l->elem[j-1] = l->elem[j];
	}

	// insert
	l->length--;

	return OK;
}

// - 遍历
Status ListTraverse(SqList l, void(Visit)(ElemType)){
	
	int i = 0;

    printf("------ visit ------\r\n");
	for(i=0; i<l.length; i++){
		Visit(l.elem[i]);
	}
    printf("\r\n---- visit end ----\r\n");

	return OK;
}

// 线性表顺序结构及基本操作(测试文件)
// file_name: 2_1_test.c

#include "2_1.h"

int main(){

	printf("------------------------------test-------------------------------\r\n");

	SqList sl;
	int i = 0;
	ElemType e = 0;
	ElemType pre_e, next_e;
	
	// init
	if(OK == InitList(&sl)){
		printf("init OK!\r\n");
	}else{
		printf("init failed.\r\n");
		return 0;
	}

	// insert
	for(i=1; i<20; i++){
		if(OK == ListInsert(&sl, i, (ElemType)i)){
			printf("insert %d ok.\r\n", i);
		}else{
			printf("insert %d failed.\r\n", i);
		}
	}

	// traverse
	if(OK == ListTraverse(sl, Visit)){
		printf("traverse over.\r\n");
	}else{	
		printf("traverse failed.\r\n");
	}

	// length
	printf("the length of list: %d\r\n", ListLength(sl));

	// delete
	i = 5;
	if(OK == ListDelete(&sl, i, &e)){
		printf("del the %d elem, value is: %d\r\n", i, e);
	}else{
		printf("del the %d elem failed.\r\n", i);
	}

	// traverse
	if(OK == ListTraverse(sl, Visit)){
		printf("traverse over.\r\n");
	}else{	
		printf("traverse failed.\r\n");
	}

	// length
	printf("the length of list: %d\r\n", ListLength(sl));

	// getelem
	i = 3;
	e = 0;
	if(OK == GetElem(sl, i, &e)){
		printf("get elem OK, the %d elem is: %d\r\n", i, e);
	}else{
		printf("get elem failed.\r\n");
	}

	// locateElem
	e = 7;
	int ret = LocateElem(sl, e, Compare);
	if(ret > 0){
		printf("the elem of %d, order is: %d\r\n", e, ret);
	}else{
		printf("the elem not exist in list.\r\n");
	}

	// prior
	e = 3;
	if(OK == PriorElem(sl, e, &pre_e)){
		printf("the pre of %d is: %d\r\n", e, pre_e);	
	}else{
		printf("find the pre of %d failed.\r\n", e);
	}

	// next
	e = 3;
	if(OK == NextElem(sl, e, &next_e)){
		printf("the next of %d is: %d\r\n", e, next_e);	
	}else{
		printf("find the next of %d failed.\r\n", e);
	}

	// clear
	ClearList(&sl);

	// empty
	if(OK == ListEmpty(sl)){
		printf("now the list is empty.\r\n");
	}else{
		// length
		printf("the length of list: %d\r\n", ListLength(sl));
	}

	// destroy
	DestroyList(&sl);

	printf("------------------------------end--------------------------------\r\n");

	return 0;
}

# 结果输出
ubuntu@ubuntu:~/work/c/algo$ gcc 2_1_test.c 2_1.c 
ubuntu@ubuntu:~/work/c/algo$ ./a.out 
------------------------------test-------------------------------
init OK!
insert 1 ok.
insert 2 ok.
insert 3 ok.
insert 4 ok.
insert 5 ok.
insert 6 ok.
insert 7 ok.
insert 8 ok.
insert 9 ok.
insert 10 ok.
insert 11 ok.
insert 12 ok.
insert 13 ok.
insert 14 ok.
insert 15 ok.
insert 16 ok.
insert 17 ok.
insert 18 ok.
insert 19 ok.
------ visit ------
1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  
---- visit end ----
traverse over.
the length of list: 19
del the 5 elem, value is: 5
------ visit ------
1  2  3  4  6  7  8  9  10  11  12  13  14  15  16  17  18  19  
---- visit end ----
traverse over.
the length of list: 18
get elem OK, the 3 elem is: 3
the elem of 7, order is: 6
the pre of 3 is: 2
the next of 3 is: 4
now the list is empty.
------------------------------end--------------------------------
ubuntu@ubuntu:~/work/c/algo$ 

2、线性表扩展(有a、b两个线性表,扩展a表,把b表中有而a表中没有的插入a表)

思路:循环遍历 b表元素,判断是否已经在 a中出现过,1.出现过则跳过,2.未出现则插入 a表尾部;

// 线性表扩展
#include "2_1.h"

// union
Status Union(SqList *sl_a, SqList *sl_b){
	
	int i = 0;
	ElemType e;
	int p = sl_a->length;

	for(i=1; i<=sl_b->length; i++){
		if(OK == GetElem(*sl_b, i, &e)){
			// compare
			if(LocateElem(*sl_a, e, Compare) <= 0){
				// insert
				if(OK == ListInsert(sl_a, ++p, e)){
					printf("insert list OK.\r\n");
				}else{
					printf("insert list failed.\r\n");
				}
			}else{
				printf("the elem:%d has already in list.\r\n", e);
			}
		}else{
			printf("get elem at pos:%d failed.\r\n", i);
		}
	}
	
	return OK;
}

int main(void){
	
	int i = 0;
	int ret = 0;
	SqList sl_a, sl_b;

	ElemType arr_a[5] = {8, 4, 2, 1, 9};
	ElemType arr_b[9] = {8, 3, 0, 5, 6, 7, 9, 10, 11};

	// 0. init
	ret = InitList(&sl_a);
	if(OK == ret){
		printf("init list OK.\r\n");
	}else{
		printf("init list failed.\r\n");
	}
	ret = InitList(&sl_b);
	if(OK == ret){
		printf("init list OK.\r\n");
	}else{
		printf("init list failed.\r\n");
	}

	// 1. insert
	int len_a, len_b;
	len_a = sizeof(arr_a)/sizeof(ElemType);
	len_b = sizeof(arr_b)/sizeof(ElemType);

	for(i=0; i<len_a; i++){
		if(OK == ListInsert(&sl_a, i+1, arr_a[i])){
			printf("insert %d to list OK.\r\n", arr_a[i]);
		}else{
			printf("insert %d to list failed.\r\n", arr_b[i]);
		}
	}

	for(i=0; i<len_b; i++){
		if(OK == ListInsert(&sl_b, i+1, arr_b[i])){
			printf("insert %d to list OK.\r\n", arr_b[i]);
		}else{
			printf("insert %d to list failed.\r\n", arr_b[i]);
		}
	}

	// 2. print
	ListTraverse(sl_a, Visit);
	ListTraverse(sl_b, Visit);

	// 3. union
	if(OK == Union(&sl_a, &sl_b)){
		printf("union OK.\r\n");
	}else{
		printf("union failed.\r\n");	
	}	

	// 4. print
	ListTraverse(sl_a, Visit);

	return 0;
}

# 输出结果
ubuntu@ubuntu:~/work/c/algo$ gcc 2_2.c 2_1.c
ubuntu@ubuntu:~/work/c/algo$ ./a.out 
init list OK.
init list OK.
insert 8 to list OK.
insert 4 to list OK.
insert 2 to list OK.
insert 1 to list OK.
insert 9 to list OK.
insert 8 to list OK.
insert 3 to list OK.
insert 0 to list OK.
insert 5 to list OK.
insert 6 to list OK.
insert 7 to list OK.
insert 9 to list OK.
insert 10 to list OK.
insert 11 to list OK.
------ visit ------
8  4  2  1  9  
---- visit end ----
------ visit ------
8  3  0  5  6  7  9  10  11  
---- visit end ----
the elem:8 has already in list.
insert list OK.
insert list OK.
insert list OK.
insert list OK.
insert list OK.
the elem:9 has already in list.
insert list OK.
insert list OK.
union OK.
------ visit ------
8  4  2  1  9  3  0  5  6  7  10  11  
---- visit end ----
ubuntu@ubuntu:~/work/c/algo$ 

3、线性表合并(有a、b两个非递减有序线性表,将a、b归并为c表,c表扔按非递减排列)

思路:因为 a、b 是已经排序的顺序表,只要相互比较取数放到 c 中即可;

相互比较分为两种情况:元素和后继元素比较;元素和另一个表中定位元素比较;

此时只需要记录当前位置即可;

// 线性表合并
#include "2_1.h"

// merge
Status MergeList(SqList *sl_a, SqList *sl_b, SqList *sl_c){
	
	ElemType e_a, e_b, e_c;
	int i = 0;
	int cur_a = 1;
	int cur_b = 1;
	int len_a = sl_a->length;
	int len_b = sl_b->length;
	int len_c = len_a + len_b;
	
	for(i=1; i<=len_c; i++){
		if(cur_a<=len_a && cur_b<=len_b){
			GetElem(*sl_a, cur_a, &e_a);
	   		GetElem(*sl_b, cur_b, &e_b);
			if(e_a > e_b){	
				e_c = e_b;
				cur_b++;
			}else{
				e_c = e_a;
				cur_a++;
			}
		}else{
			if(cur_a <= len_a){
				GetElem(*sl_a, cur_a, &e_a);
				e_c = e_a;
				cur_a++;	
			}
			if(cur_b <= len_b){
	   			GetElem(*sl_b, cur_b, &e_b);
				e_c = e_b;
				cur_b++;	
			}
		}

		if(OK == ListInsert(sl_c, i, e_c)){
			printf("insert %d to list_c OK.\r\n", e_c);
		}else{
			printf("insert %d to list_c Failed.\r\n", e_c);
		}
	}
	
	return OK;
}

int main(void){
	
	int i = 0;
	int ret = 0;
	SqList sl_a, sl_b, sl_c;

	ElemType arr_a[8] = {1, 3, 5, 6, 6, 9, 22, 33};
	ElemType arr_b[12] = {2, 3, 3, 5, 6, 7, 7, 9, 10, 11, 12, 32};

	// 0. init
	ret = InitList(&sl_a);
	if(OK == ret){
		printf("init list OK.\r\n");
	}else{
		printf("init list failed.\r\n");
	}
	ret = InitList(&sl_b);
	if(OK == ret){
		printf("init list OK.\r\n");
	}else{
		printf("init list failed.\r\n");
	}
	ret = InitList(&sl_c);
	if(OK == ret){
		printf("init list OK.\r\n");
	}else{
		printf("init list failed.\r\n");
	}

	// 1. insert
	int len_a, len_b;
	len_a = sizeof(arr_a)/sizeof(ElemType);
	len_b = sizeof(arr_b)/sizeof(ElemType);

	for(i=0; i<len_a; i++){
		if(OK == ListInsert(&sl_a, i+1, arr_a[i])){
			printf("insert %d to list OK.\r\n", arr_a[i]);
		}else{
			printf("insert %d to list failed.\r\n", arr_b[i]);
		}
	}

	for(i=0; i<len_b; i++){
		if(OK == ListInsert(&sl_b, i+1, arr_b[i])){
			printf("insert %d to list OK.\r\n", arr_b[i]);
		}else{
			printf("insert %d to list failed.\r\n", arr_b[i]);
		}
	}

	// 2. print
	ListTraverse(sl_a, Visit);
	ListTraverse(sl_b, Visit);
	ListTraverse(sl_c, Visit);

	// 3. merge
	if(OK == MergeList(&sl_a, &sl_b, &sl_c)){
		printf("union OK.\r\n");
	}else{
		printf("union failed.\r\n");	
	}	

	// 4. print
	ListTraverse(sl_c, Visit);

	return 0;
}

# 输出结果
ubuntu@ubuntu:~/work/c/algo$ gcc 2_3.c 2_1.c 
ubuntu@ubuntu:~/work/c/algo$ ./a.out 
init list OK.
init list OK.
init list OK.
insert 1 to list OK.
insert 3 to list OK.
insert 5 to list OK.
insert 6 to list OK.
insert 6 to list OK.
insert 9 to list OK.
insert 22 to list OK.
insert 33 to list OK.
insert 2 to list OK.
insert 3 to list OK.
insert 3 to list OK.
insert 5 to list OK.
insert 6 to list OK.
insert 7 to list OK.
insert 7 to list OK.
insert 9 to list OK.
insert 10 to list OK.
insert 11 to list OK.
insert 12 to list OK.
insert 32 to list OK.
------ visit ------
1  3  5  6  6  9  22  33  
---- visit end ----
------ visit ------
2  3  3  5  6  7  7  9  10  11  12  32  
---- visit end ----
------ visit ------

---- visit end ----
insert 1 to list_c OK.
insert 2 to list_c OK.
insert 3 to list_c OK.
insert 3 to list_c OK.
insert 3 to list_c OK.
insert 5 to list_c OK.
insert 5 to list_c OK.
insert 6 to list_c OK.
insert 6 to list_c OK.
insert 6 to list_c OK.
insert 7 to list_c OK.
insert 7 to list_c OK.
insert 9 to list_c OK.
insert 9 to list_c OK.
insert 10 to list_c OK.
insert 11 to list_c OK.
insert 12 to list_c OK.
insert 22 to list_c OK.
insert 32 to list_c OK.
insert 33 to list_c OK.
union OK.
------ visit ------
1  2  3  3  3  5  5  6  6  6  7  7  9  9  10  11  12  22  32  33  
---- visit end ----
ubuntu@ubuntu:~/work/c/algo$ 


—— 2018-12-03 ——

你可能感兴趣的:(●,【,数据结构和算法,】)