typedef struct
{
int *list;
int length;//数据存储个数
int size;//申请的内存单元个数
}MYLIST;
已知线性表:MYLIST *myList;
1、初始化线性表 //实质就是对list指针进行初始化,此处我们选择动态初始化
initList(MYLIST* &temp)
{
temp->list = (List*)malloc(sizeof(List)*10);
if(!temp)
exit -1;
temp->length = 0;
temp->size = 10;
}
//思考:函数内使用静态初始化是否可行?
如下图所示,函数内的数组为局部变量,实参取到的值为随机值,并不是函数内的实际值。
上述问题解决办法:
在局部变量aa前添加static,延长aa的生命周期,此时取出的就是函数内局部变量的值了。
小结:可以发现动态存储和静态存储的区别:动态存储可以realloc进行增加内存,但是静态存储就没有办法了,所以还是选择动态存储。
2、销毁线性表//实质就是对释放list所指向的内存空间,针对动态申请的内存
destroyList(MYLIST* &temp)
{
free(temp.list);
temp->list = NULL;
temp->length = 0;
temp->size = 0;
}
3、线性表置空
clearList(MYLIST *&temp)
{
temp->length = 0;//意为,其中的数据可以随意覆盖。
}
4、线性表是否为空
bool isEmptyList(MYLIST* temp)
{
if(temp->length==0)//数据长度为0,就认为线性表为空。
return true;
else
return false;
}
5、线性表数据长度
int lengthList(MYLIST* temp)
{
return temp->length;
}
6、获取线性表中第n个元素
getElemList(MYLIST* temp,int n, int &value)
{
if(n>temp->length||n<1)
return ERROR;
else
{
value = temp->list[n-1];//->与[]同运算级,结合性从左至右
reuturn OK;
}
}
7、在线性表的第n个位置插入元素// n的范围是1--length+1,因为可以在最后一个元素的后面新增一个元素
insertElemList(MYLIST* &temp,int n,int value)
{
if(n<1||n>temp->length+1)
return ERROR;
if(temp->length==temp->size)//空间已满
{
int*add = (int*)realloc(temp->list,(temp->size+1)*sizeof(int));
if(!add)
exit -1;
for(int i=temp->length-1; i>=n-1;i--)//转化为数组的下标,最后一个下标和第n个下标
{
temp->list[i+1]= temp->list[i];
}
temp->list[i+1]= value;
}else //空间没满
{
for(int i=temp->length-1; i>=n-1;i--)//转化为数组的下标,最后一个下标和第n个下标
{
temp->list[i+1]= temp->list[i];
}
temp->list[i+1]= value;
}
temp->length++;
temp->size++;
}
以上程序,发现空间满与不满,代码有重复的地方,故可以合并如下:
insertElemList(MYLIST* &temp,int n,int value)
{
if(n<1||n>temp->length+1)
return ERROR;
if(temp->length==temp->size)//空间已满
{
int*add = (int*)realloc(temp->list,(temp->size+1)*sizeof(int));
if(!add)
exit -1;
temp->list = add;
}
for(int i=temp->length-1; i>=n-1;i--)//转化为数组的下标,最后一个下标和第n个下标
{
temp->list[i+1]= temp->list[i];
}
temp->list[i+1]= value;
temp->length++;
temp->size++;
}
以上代码可以这么理解:空间满,申请一个空间,那么空间就不满了,就与空间不满代码一致了。
8、线性表中删除第n个元素
deleteElemList(MYLIST * &temp,int n,int &elem)
{
if(n>temp->length||n<1)
return ERROR;
int* p = temp->list+n-1;
elem = *p;
int* q = temp->list+temp->length-1;//q指向线性表中最后一个元素
for(; p<=q-1;p++)
{
*p = *(p+1);
}
temp->length--;
}
9、线性表中取某元素的直接前驱
bool priorElemList(MYLIST temp, int value ,int &ret)
{
int *p = temp->list;
for(;p<=temp->list+length-1;p++)
{
if(*P==value)
{
if(p !=temp->list) //除了第一个元素外,都有直接前驱
{
ret = *(p-1);
return true;
}
}
}
return false;
}
分析:上述例子是一个常规的,正向的分析思路,即,在遍历线性表中的元素,找到符合条件的那个值。
那么,也可以进行反向的分析,即,遍历线性表中元素,剔除掉不符合条件的值,剩下的那个就是符合条件的值。
bool priorElemList(MYLIST temp, int value ,int &ret)
{
int *p = temp->list;
for(;p<=temp->list+length-1;p++)
{
if(*P!=value)
continue;
else
break;
}
if(p !=temp->list&&p!=temp->list+length)//跳出循环2种情况:一种是break一种是for循环结束;
{
ret = *(p-1); // 或者没有进入循环
return true;
}
return false;
}
上文中的for循环又可以改写成以下:因为,for循环(while循环)本来就是满足循环条件执行循环体,不满足跳出循环,且循环其实就是多个if的表达-----不满足条件执行{}外的语句。
for(;p<=temp->list+length-1;p++)
{
if(*P!=value)
continue;
else
break;
}
//上例又可以改写成如下:
for(;p<=temp->list+length-1&&*P!=value;p++) ;//不满足循环条件,退出
if(p<=temp->list+length-1)
{
ret = *(p-1);
return true;
}
return false;
//故退出for循环后,p>temp->list+length-1 或者 *p==value;
//此时只需排除上述两者可能的一种,就一定是另一种可能。
//理解:有件事,是A或者B做的,已知不是A,那么肯定就是B了。
//另外,上例又可以改写成while循环示例:
while(p<=temp->list+length-1&&*P!=value) p++;
10、线性表中取某元素的直接后继
nextElemList(MYLIST temp,int value, int &ret)
{
int *p = temp->list;
for(;p<temp->list+temp->length-1&&*p!=value;p++)
{
}
if(p<temp->list+temp->length-1)
{
ret = *(p+1);
return true;
}
return false;
}
11、线性表中查找与值满足某函数关系的第n个元素
int findElemList(MYLIST* temp,int value,bool(*myfunc)(int,int))
{
int *p = temp->list;
int n = 1;
for(;p<temp->list+temp->length && !myfunc(value,*p);p++,n++)
{
}
if(p<temp->list+temp->length)
{
return n;
}
return 0;
}