1.线性表的动态分配顺序存储结构
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef struct{
Elemtype *elem;
int length;
int listsize;
}Sqlist;
ps:length是目前长度,listsize是固定长度
2.将两个有序顺序表La与Lb归并为有序顺序表Lc
我的版本:
思路:设置三个游标ijk,分别指向三个顺序表。当ij指向元素,比较大小,插入到表c中。
注意:当一个表元素比较完之后,另一个直接顺序插入c中。
老师的版本:
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归并指针实现
思路:
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++;
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; 先指针后移,然后取值。即取指针指向的下一个元素的值。