复习ppt第一课:顺序表

1.线性表的动态分配顺序存储结构

#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef struct{
Elemtype *elem;
int length;
int listsize;
}Sqlist;

ps:length是目前长度,listsize是固定长度

2.将两个有序顺序表LaLb归并为有序顺序表Lc

我的版本:

思路:设置三个游标ijk,分别指向三个顺序表。当ij指向元素,比较大小,插入到表c中。

注意:当一个表元素比较完之后,另一个直接顺序插入c中。

老师的版本:

思路 : 共设 ijk 三个游标 , ij 分别遍历 La Lb 中元素, k 指向 c 中待插入位置。只要两表还有元素,则比较当前指向的两个元素,较小的插入 Lc k 号位置。
注意:一表先空,另表余块逐个插入 Lc Lc 初始化 k 递增
 
Status ListMerge_SortedSq(SqList La, SqList Lb, SqList& Lc) {
//将两个有序顺序表La与Lb归并为有序顺序表Lc
	int i = 1, j = 1, k = 1;
	int la_len = ListLength_Sq(La);
	int lb_len = ListLength_Sq(Lb);
	InitList_Sq(Lc);
	ElemType a, b;
	while (i <= la_len && j <= lb_len) {//归并
		GetElem_Sq(La, i, a);
		GetElem_Sq(Lb, j, b);
		if (i <= j) {
			ListInsert_Sq(Lc, k, a);
			i++;
			k++;
		}
		else {
			ListInsert_Sq(Lc, k, b);
			j++;
			k++;
		}
	}
	while (i <= la_len) { //插入La的剩余元素
		GetElem_Sq(La, i, a);
		ListInsert_Sq(Lc, k, a);
		i++;
		k++;
	}
	while (j <= lb_len) { //插入Lb的剩余元素
		GetElem_Sq(Lb, j, b);
		ListInsert_Sq(Lc, k, b);
		j++;
		k++;
	}
	return OK;
}

详细代码书写思路:

归并:设游标,当游标还指向元素(没走到最后,比表长小。所以需要获得表长ListLength_Sq(La) ),首先要得到游标指向的元素数值GetElem_Sq(La, i, a),再去比较大小。比完之后执行插入操作ListInsert_Sq(Lc, k, a)。  最后是特殊情况处理。

综上所述,大概思路是是获得游标指向的数值,比大小,插入。

需要引用的函数时 求表长,取值,插入。

ListLength_Sq(La)

GetElem_Sq(La, i, a)     再a表中第i个位置得到数值a

ListInsert_Sq(Lc, k, a)

ps:位序从1开始,下标从0开始

2.1归并指针实现

思路:

设指针pa pb分别遍历La与Lb中元素.pc指向待Lc待插入位置. 比较pa/pb所指元素,小者通过pc插入.
注意:余块插入;Lc初始化;插入位置递增
void MergeList_Sq(SqList La, SqList Lb, Sqlist& Lc) {
	Lc.listsize = La.length + Lb.length; 
	Lc.length = Lc.listsize;
	Lc.elem = (ElemType*)malloc(Lc.listsize * sizeof(ElemType));
	if (!Lc.elem)
		exit(OVERFLOW);
	ElemType* pa = La.elem;
	ElemType* pb = Lb.elem;
	ElemType* pc = Lc.elem;
	ElemType* pa_last = La.elem + La.length - 1;
	ElemType* pb_last = Lb.elem + Lb.length - 1;
	while (pa <= pa_last && pb <= pb_last)
	{
		if (*pa <= *pb)
		{
			*pc = *pa;
			pa++;
			pc++;
		}
		else {
			*pc = *pb;
			pb++;
			pc++;
		}

	}
	while (pa <= pa_last) {
		*pc++ = *pa++;
	}
	while (pb < pb_last) {
		*pc++ = *pb++;
	}
}

详细代码书写思路:
归并,给指针赋值,得到表长好比较,比较大小,值比较,指针后移。最后特殊情况处理。
*pc++=*pa++; 
等价于
*pc=*pa;
pc++;
pa++;
一个细节是c表要初始化操作。表长,开辟空间,分配失败处理。

3.顺序表基础操作

 InitList(&L)     DestroyList(&L)

ClearList(&L)
ListInsert(&L,i,e) //1≤i≤ListLength(L)+1;表长+1
 ListDelete(&L,i,&e)//1≤i≤ListLength(L);表长减1
 
 ListEmpty(L)    ListLength(L)   GetElem(L,i,&e)
 LocateElem(L,e,compare()) //返回位序,找不到返0
 PriorElem(L,cur_e,&pre_e)
 NextElem(L,cur_e,&next_e)
 ListTraverse(L,visit())

3.1初始化顺序表

Status InitList_Sq(SqList& L) {
	L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
	if (!L.elem)
		exit(OVERFLOW);
	L.length = 0;
	L.lisize = LIST_INIT_SIZE;
	return OK;
}

注意:开辟空间的写法  溢出判断  初始化表长为0,“空”表  初始化存储容量

3.2删除操作(指针实现)

void ListDelete_Sq(SqList& L, int i, ElemType& e) {
	if (i<1 || i>L.length)
		return ERROR;
	ElemType* p;//p是被删除元素的位置
	ElemType* q;
	p = L.elem[i - 1];//L.elem+i-1
	q = L.elem + L.length - 1;//L.elem[L.length-1]
	e = *p;//被删除元素的值赋给e
	while (p < q) {
		*p = *(p + 1);
		p++;
	}
   //while(p <= q) 
   // *(p - 1) = *p;
	L.length--;
	return OK;
}

详细代码思路:删除的整体思路是元素前移,所以要有被删除元素位置和表尾元素位置。

位置就想到数组下标或者指针

若用指针做的话,设两个指针变量,分别指向被删位置和表尾位置。同时因为要传回被删元素值,所以被删元素的值要复制一下。下面就开始元素前移,注意while条件和元素迁移的匹配。最后表长记得减。

总体思路是:判断越界,被删元素的值传回,从被删位置到表尾位置元素前移,表长减1。

难点:位置如何用指针表示,循环的时候注意匹配,防止越界。

小技巧:删除的核心是元素前移,所以p指向前面,q指向表尾。判断条件是p<=q,相对应的是

*(p -1) = *p;

插入的核心是元素后移,所以p指向表尾,q指向前面。判断条件是q<=p,相对应的是

*(p +1) = *p;

3.3插入操作(指针操作)

Status ListInsert_Sq(SqList& L, int i, ElemType e) {
	if (i<1 || i>L.length)
		return ERROR;
	if (L.length >= L.listsize) {
		L.elem = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));
		if (!L.elem)
			exit OVERFLOW;
		L.listsize += LISTINCREMNET;
	}
	ElemType* q = L.elem + i - 1;
	ElemType* p = L.elem + L.length - 1;
	while (p >= q) {
		*(p + 1) = *p;
		p--;
	}
	*q = e;
	L.length++;
	return OK;
}

思路:首先判断插入位置是否合法,其次判断插入后表长是否合法,若超出长度需要扩容(length实际长度,listsize固定长度)。然后开始元素后移,设两个指针,p指向最后位置,q指向插入位置。插入元素赋值。最后一定要表长+1。

注意while条件和指针移动的匹配性。

犯的错误:插入的核心思想是元素后移

3.4剩余顺序表基础操作(书本)

1.销毁顺序表

void DestroyList(Sqlist& L) {
	free(L.elem);
	L.elem = NULL;
	L.length = 0;
	L.listsize = 0;
}

2.重置清空顺序表

void ClearList(Sqlist& L) {
	L.length = 0;
}

3.判断是否是空表

Status ListEmpty(Sqlist& L) {
	if (L.length == 0)
		return TRUE;
	else
		return FALSE;
}

4.求表长

int ListLength(Sqlist L) {
	return L.length;
}

5.返回特定值

Status GetElem(Sqlist L, int i, ElemType& e) {
	if (i<1 || i>L.length)
		return ERROR;
	e = *(L.elem + i - 1);
	return OK;
}

注意:首先是参数定义,顺序表、位置、和要返回的值

          其次是位置判断是否合法

         最后是赋值操作。

区别赋值和插入

赋值:    e = *(L.elem + i - 1)  把第i个位置的元素值赋给e,并返回  

插入:*q=e  把元素e的值插入到q指针指向的位置,将值赋给指针指向的内存空间

指针在等号左边和右边的区别:

*p出现在右边是值,表示p指向的int型变量的值

*p出现在左边是指向,表示p指向int型变量的内存空间,可以将等号右边的值赋给这一内存空间

6.返回特定值的位序

int LocateElem(Sqlist L, ElemType e, Status(*compare)(ElemType, ElemType) {
	int i = 1;
	ElemType* p = L.elem;
	while (i <= L.length && !compare(*p++, e))
		i++;
	if (i <= L.length)
		return i;
	else
		return 0;
}

注意:i是位序,位序从1开始。区分位序和下标。

          p++是指针后移,*p++是指针下一个指向的值

7.返回前驱值

Status PriorElem(SqList L, ElemType cur_e, ElemType& pre_e)
{
	int i=2;
	ElemType* p = L.elem + 1;
	while (i <= L.length && *p != cur_e)
	{
		i++;
		p++;
	}
	if (i > L.length)
		return ERROR;
	else
	{
		pre_e = *--p;
		return OK;
	}
}

注意:位序从2开始。循环的判断条件是在表长范围内且指针指向的值不等于cur_e

          若在表长范围内找到该值,则返回指针指向的前一个内存空间的值赋给pre_e

i++和++i的区别:i++ 返回原来的值,++i 返回加1后的值。

8.返回后继值

Status NextElem(SqList L, ElemType cur_e, ElemType& next_e)
{
	int i=1;
	ElemType* p = L.elem +;
	while (i <= L.length && *p != cur_e)
	{
		i++;
		p++;
	}
	if (i == L.length)
		return ERROR;
	else
	{
		next_e = *++p;
		return OK;
	}
}

注意:找不到的情况判定条件是i==L.length

而前驱的判定条件是i>L.length

9.遍历元素

void ListTraverse(Sqlist L, void((* visit)(ElemType&))
{
	ElemType* p = L.elem;
	int i;
	for (i = i; i <= L.length; i++)
	{
		visit(*p++);
	}
	printf("\n");
}

注意:*p++与*++p的区别

*p++:等同于:*p;  p = p+1;  先取值,然后指针后移。即取当前值,指针后移。

*++p:等同于 p = p+1;    *p;  先指针后移,然后取值。即取指针指向的下一个元素的值。

4.算法实现

4.1抽象线性表类型

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值