2-1-单链表顺序存储结构-线性表-第2章-《数据结构》课本源码-严蔚敏吴伟民版

概述

数据结构的学习当然要从线性表学起,而线性表里首先需要学习单链表,这里从单链表最简单的顺序存储结构(本质就是可变数组存储)开始。

解析

单链表强调元素在逻辑上紧密相邻,所以首先想到用数组存储。但是普通数组有着无法克服的容量限制,在不知道输入有多少的情况下,很难确定出一个合适的容量。对此,一个较好的解决方案就是使用动态数组。首先用malloc申请一块拥有指定初始容量的内存,这块内存用作存储单链表元素,当录入的内容不断增加,以至于超出了初始容量时,就用calloc扩展内存容量,这样就做到了既不浪费内存,又可以让单链表容量随输入的增加而自适应大小。

   单链表顺序存储结构如下图:

可能涉及到的语法难点

刚接触数据结构的同学,单链表顺序存储结构可能会是其面对的第一个坎。这里涉及到了结构体、动态数组、结构指针,甚至还有函数变量(函数做参数,本质是函数指针),所以需要有相对扎实的语言语法基础。当然,这也并不是说一定得掌握了高级语法才能开始学习数据结构,可以先将语言学到入门(入门意味着学会了提问),再边学数据结构边巩固语法。一定要亲自动手写一写,否则,肯定学不好。

源码 SequenceList-mian.c

/***************************************
 *                                     *
 * 文件夹: ▲02 线性表\01 SequenceList *
 *                                     *
 * 内  容: 单链表顺序结构相关函数测试  *
 *                                     *
 ***************************************/

#include <stdio.h>
#include "SequenceList.c" 								//**▲02 线性表**//

/* 测试调用的函数原型 */
Status CmpGreater(LElemType_Sq e, LElemType_Sq data);
	//若data>e,返回TRUE,否则返回FALSE
	
void PrintElem(LElemType_Sq e);
	//测试函数,打印整型 

int main(int argc, char **argv)
{
	SqList L;
	int i;
	LElemType_Sq e;

	printf("▼1\n▲函数 InitList_Sq 测试...\n");		//1.函数InitList_Sq测试
	{
		printf("初始化顺序表 L ...\n");					 
		InitList_Sq(&L);
		printf("\n");	
	}
	PressEnter;
	
	printf("▼4\n▲函数 ListEmpty_Sq 测试...\n");		//4.函数ListEmpty_Sq测试
	{
		ListEmpty_Sq(L) ? printf(" L 为空!!\n") : printf(" L 不为空!\n");
		printf("\n");	
	}
	PressEnter;
		
	printf("▼10\n▲函数 ListInsert_Sq 测试...\n");		//10.函数ListInsert_Sq测试
	{
		for(i=1; i<=6; i++)									
		{
			printf("作为示范,在 L 第 %d 个位置插入 \"%d\"...\n", i, 2*i);
			ListInsert_Sq(&L, i, 2*i);
		}
		printf("\n");	
	}
	PressEnter;
			
	printf("▼12\n▲函数 ListTraverse_Sq 测试...\n");	//12.函数ListTraverse_Sq测试
	{
		printf(" L 中的元素为:L = ");						 
		ListTraverse_Sq(L, PrintElem);
		printf("\n\n");	
	}
	PressEnter;
		
	printf("▼5\n▲函数 ListLength_Sq 测试...\n");		//5.函数ListLength_Sq测试
	{
		i = ListLength_Sq(L);
		printf(" L 的长度为 %d \n", i);
		printf("\n");	
	}
	PressEnter;
			
	printf("▼11\n▲函数 ListDelete_Sq 测试...\n");		//11.函数ListDelete_Sq测试
	{
		ListDelete_Sq(&L, 6, &e);
		printf("删除 L 中第 6 个元素 \"%d\" ...\n", e);
		printf(" L 中的元素为:L = ");						 
		ListTraverse_Sq(L, PrintElem);
		printf("\n\n");
	}
	PressEnter;
		
	printf("▼6\n▲函数 GetElem_Sq 测试...\n");			//6.函数GetElem_Sq测试
	{
		GetElem_Sq(L, 4, &e);
		printf(" L 中第 4 个位置的元素为 \"%d\" \n", e);
		printf("\n");
	}
	PressEnter;
		
		
	printf("▼7\n▲函数 LocateElem_Sq 测试...\n");	  	//7.函数LocateElem_Sq测试
	{
		i = LocateElem_Sq(L, 7, CmpGreater);
		printf(" L 中第一个元素值大于 \"7\" 的元素的位置为 %d \n", i); 
		printf("\n");
	}
	PressEnter;
		
	printf("▼8\n▲函数 PriorElem_Sq 测试...\n");		//8.函数PriorElem_Sq测试
	{
		PriorElem_Sq(L, 6, &e);
		printf("元素 \"6\" 的前驱为 \"%d\" \n", e);
		printf("\n");
	}
	PressEnter;
		
	printf("▼9\n▲函数 NextElem_Sq 测试...\n");		//9.函数NextElem_Sq测试
	{
		NextElem_Sq(L, 6, &e);
		printf("元素 \"6\" 的后继为 \"%d\" \n", e);
		printf("\n");
	}
	PressEnter;
		
	printf("▼2\n▲函数 ClearList_Sq 测试...\n");		//2.函数ClearList_Sq测试
	{
		printf("清空 L 前:");
		ListEmpty_Sq(L) ? printf(" L 为空!!\n") : printf(" L 不为空!\n");		
		ClearList_Sq(&L);
		printf("清空 L 后:");
		ListEmpty_Sq(L) ? printf(" L 为空!!\n") : printf(" L 不为空!\n");
		printf("\n");
	}
	PressEnter;
		
	printf("▼3\n▲函数 DestroyList_Sq 测试...\n");		//3.函数DestroyList_Sq测试
	{
		printf("销毁 L 前:");
		L.elem ? printf(" L 存在!\n") : printf(" L 不存在!!\n");
		DestroyList_Sq(&L);
		printf("销毁 L 后:");
		L.elem ? printf(" L 存在!\n") : printf(" L 不存在!!\n");
		printf("\n");
	}
	PressEnter;
		
	return 0;
}

Status CmpGreater(LElemType_Sq e, LElemType_Sq data)
{
	return data>e ? TRUE : FALSE;
}

void PrintElem(LElemType_Sq e)
{
	printf("%d ", e);
}

源码 SequenceList.c

/***************************************
 *                                     *
 * 文件夹: ▲02 线性表\01 SequenceList *
 *                                     *
 * 文件名: SequenceList.c              *
 *                                     *
 * 算  法: 2.3、2.4、2.5、2.6          * 
 *                                     *
 ***************************************/

#ifndef SEQUENCELIST_C
#define SEQUENCELIST_C

#include "SequenceList.h" 				//**▲02 线性表**//

/*════╗
║算法2.3 ║ 
╚════*/
Status InitList_Sq(SqList *L)
{
	(*L).elem = (LElemType_Sq*)malloc(LIST_INIT_SIZE*sizeof(LElemType_Sq));
	if(!(*L).elem)
		exit(OVERFLOW); 				//分配内存失败

	(*L).length = 0;					//初始化顺序表长度为0
	(*L).listsize = LIST_INIT_SIZE;		//顺序表初始内存分配量

	return OK;							//初始化成功	 
} 

void ClearList_Sq(SqList *L)
{
	(*L).length = 0;
}

void DestroyList_Sq(SqList *L)
{
	free((*L).elem);

	(*L).elem = NULL;					//释放内存后置空指针 
	(*L).length = 0;
	(*L).listsize = 0;
}

Status ListEmpty_Sq(SqList L)
{
	return 	L.length==0 ? TRUE : FALSE;
}

int ListLength_Sq(SqList L)
{
	return L.length;	
}

Status GetElem_Sq(SqList L, int i, LElemType_Sq *e)
{ 
	if(i<1 || i>L.length)
		return ERROR;					//i值不合法
	else
		*e = L.elem[i-1];

	return OK;
}

/*════╗
║算法2.6 ║ 
╚════*/
int LocateElem_Sq(SqList L, LElemType_Sq e, Status(Compare)(LElemType_Sq, LElemType_Sq))
{
	int i = 1;							//i的初值为第一个元素的位序
	
	while(i<=L.length && !Compare(e, L.elem[i-1]))
		++i;

	if(i<=L.length)
		return i;
	else
		return 0; 
}

Status PriorElem_Sq(SqList L, LElemType_Sq cur_e, LElemType_Sq *pre_e)
{
	int i = 1;
	
	if(L.elem[0]!=cur_e)				//第一个结点无前驱 
	{
		while(i<L.length && L.elem[i]!=cur_e)
			++i;
		
		if(i<L.length)
		{
			*pre_e = L.elem[i-1];
			return OK;
		}	
	}
			
	return ERROR;
}

Status NextElem_Sq(SqList L, LElemType_Sq cur_e, LElemType_Sq *next_e)
{
	int i = 0;
	
	while(i<L.length && L.elem[i]!=cur_e)
		++i;

	if(i<L.length-1)					//最后一个结点无后继 
	{
		*next_e = L.elem[i+1];	
		return OK;
	}

	return ERROR;
}

/*════╗
║算法2.4 ║ 
╚════*/
Status ListInsert_Sq(SqList *L, int i, LElemType_Sq e)
{
	LElemType_Sq *newbase; 
	LElemType_Sq *p, *q;

	if(i<1 || i>(*L).length+1)
		return ERROR;					//i值不合法

	if((*L).length >= (*L).listsize)	//若存储空间已满,需开辟新空间 
	{
		newbase = (LElemType_Sq*)realloc((*L).elem, ((*L).listsize+LISTINCREMENT)*sizeof(LElemType_Sq));
		if(!newbase)
			exit(OVERFLOW);

		(*L).elem = newbase;
		(*L).listsize += LISTINCREMENT;
	}
	
	q = &(*L).elem[i-1];				//q为插入位置 
	
	for(p=&(*L).elem[(*L).length-1]; p>=q; --p)
		*(p+1) = *p;					//插入位置及之后的元素右移 
	
	*q = e;								//插入e 
	(*L).length++;						//表长增1

	return OK; 
}

/*════╗
║算法2.5 ║ 
╚════*/
Status ListDelete_Sq(SqList *L, int i, LElemType_Sq *e)
{
	LElemType_Sq *p, *q;
		
	if(i<1 || i>(*L).length)
		return ERROR;					//i值不合法
	
	p = &(*L).elem[i-1];				//p为被删除元素的位置 
	*e = *p;
	q = (*L).elem+(*L).length-1; 		//表尾元素位置 
	
	for(++p; p<=q; ++p)
		*(p-1) = *p;					//被删元素之后的元素左移 

	(*L).length--;						//表长减1

	return OK;
}

Status ListTraverse_Sq(SqList L, void(Visit)(LElemType_Sq))
{
	int i;

	for(i=0; i<L.length; i++)
		Visit(L.elem[i]);
	
	return OK;
}

#endif

源码SequenceList.h

/***************************************
 *                                     *
 * 文件夹: ▲02 线性表\01 SequenceList *
 *                                     *
 * 文件名: SequenceList.h              *
 *                                     *
 * 内  容: 顺序表相关操作列表          *
 *                                     *
 ***************************************/

#ifndef SEQUENCELIST_H
#define SEQUENCELIST_H

#include <stdio.h>
#include <stdlib.h>						//提供malloc、realloc、free、exit原型
#include "../../▲01 绪论/Status.h"		//**▲01 绪论**//

/* 宏定义 */
#define LIST_INIT_SIZE 100				//顺序表存储空间的初始分配量 
#define LISTINCREMENT  10				//顺序表存储空间的分配增量

/* 顺序表类型定义 */
#ifndef LELEMTYPE_SQ
#define LELEMTYPE_SQ
typedef int LElemType_Sq;
#endif

typedef struct
{
	LElemType_Sq *elem;					//存储空间基址(指向第一个结点的指针) 
	int length;							//当前顺序表长度 
	int listsize;						//当前分配的存储容量 
}SqList;								//顺序表0号单元正常使用 

/* 顺序表函数列表 */
Status InitList_Sq(SqList *L);
/*━━━━━━━━━━━━━━━┓
┃(01)算法2.3:初始化空顺序表L。┃
┗━━━━━━━━━━━━━━━*/

void ClearList_Sq(SqList *L);
/*━━━━━━━━━┓
┃(02)清空顺序表L。 ┃
┗━━━━━━━━━*/

void DestroyList_Sq(SqList *L);
/*━━━━━━━━━┓
┃(03)销毁顺序表L。 ┃
┗━━━━━━━━━*/
	  
Status ListEmpty_Sq(SqList L);
/*━━━━━━━━━━━━━┓
┃(04)判断顺序表L是否为空。 ┃
┗━━━━━━━━━━━━━*/

int ListLength_Sq(SqList L);
/*━━━━━━━━━━━━━━┓
┃(05)返回顺序表L中元素个数。 ┃
┗━━━━━━━━━━━━━━*/
	
Status GetElem_Sq(SqList L, int i, LElemType_Sq *e);
/*━━━━━━━━━━━━━━━━┓
┃(06)用e接收顺序表L中第i个元素。 ┃
┗━━━━━━━━━━━━━━━━*/

int LocateElem_Sq(SqList L, LElemType_Sq e, Status(Compare)(LElemType_Sq, LElemType_Sq));
/*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃(07)算法2.6:返回顺序表L中首个与e满足Compare关系的元素位序。┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/

Status PriorElem_Sq(SqList L, LElemType_Sq cur_e, LElemType_Sq *pre_e);
/*━━━━━━━━━━━━━━━━━┓
┃(08)用pre_e接收cur_e的前驱。      ┃
┗━━━━━━━━━━━━━━━━━*/

Status NextElem_Sq(SqList L, LElemType_Sq cur_e, LElemType_Sq *next_e);
/*━━━━━━━━━━━━━━━━━┓
┃(09)用next_e接收cur_e的后继。     ┃
┗━━━━━━━━━━━━━━━━━*/

Status ListInsert_Sq(SqList *L, int i, LElemType_Sq e);
/*━━━━━━━━━━━━━━━━━━━━━┓
┃(10)算法2.4:在顺序表L的第i个位置上插入e。┃
┗━━━━━━━━━━━━━━━━━━━━━*/

Status ListDelete_Sq(SqList *L, int i, LElemType_Sq *e);
/*━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃(11)算法2.5:删除顺序表L上第i个位置的元素,并用e返回。┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━*/

Status ListTraverse_Sq(SqList L, void (Visit)(LElemType_Sq)); 
/*━━━━━━━━━━━━━━┓
┃(12)用visit函数访问顺序表L。┃
┗━━━━━━━━━━━━━━*/

#endif

本文章转载于博客园- 康建伟。如果侵犯你的权益请联系我下架

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值