笔记中图片均来源课堂PPT
正在学习中,如果有错误欢迎指正!
一、线性表的性质
1.有且仅有一个开始节点,且该开始节点没有前趋结点。
2.有且仅有一个结束节点,且该结束节点没有后继节点。
3.其余节点均有一个前趋节点和后继节点。
第一个是线性表,而第二个是树
(课程交叉:在网络算法中,通常用邻接链表来记录图中边与顶点的关系,它比起邻接矩阵的储存空间更小,为O(m+n)。)
二、顺序表的基本操作
1.顺序表的定义
typedef struct list_type { //typedef相当于“取小名”,定义后可以用list_type这个新类型定义struct
int data[maxnum]; //用数组定义顺序表中的元素
int length; //定义顺序表长度
}mylist; //list是一个结构体类型,list相当于struct list_type,可以用来定义变量,比如说:mylist list1;
上面的list_type是标识符,而下面的list是变量类型。
其中,第二行的int也可以换成其他数据类型,可以根据需要做出调整。
2.顺序表的创建
创建顺序表,需要单独建立一个void函数,在函数里进行操作。
在建立顺序表时要注意以下几点:
1.顺序表的长度要初始化为0
2.用循环达成键盘赋值时,每次循环后要使p->length++
3.要先键盘赋值一个变量,然后再将变量的值赋给表中元素,不然编译器会加载符号
#define maxnum 20
void createlist(mylist* p) //传递的是指针
{
int i, elem;
p->length = 0;
printf("input the data");
for (i = 0; i < maxnum; i++)
{
scanf("%d", &elem);
p->data[i] = elem;
p->length++; //长度加一
}
}
3.顺序表的遍历
有了顺序表的定义之后,遍历就很简单了,只需要像c语言中数组的遍历一样,使用循环将表中的每一个元素遍历到即可。
void printlist(mylist*p)
{
if(p->length<=0) //判定表是否为空
{
printf("there is no data.");
return; //若没有直接返回
}
for(i=0;i<p->length;i++)
{
printf("%d",p->data[i]);
}
}
4.在顺序表中插入新元素
众所周知,在表中插入元素需要先给元素一个新位置,所以要挪动其他元素,把新位置腾出来,对于“腾位置”与插入元素,有两种方式:
一种是将插入元素位置后所有的元素向后挪动一个单位,然后在所插入地方插入新元素
另二种是从最后一位到所插入元素向后挪动一个单位,然后在所插入位置插入新元素
两种方法乍一看没有什么大的区别,似乎唯一的不同就是挪元素的起始位置,但是使用两种方法得到的结果实际上完全不一样:
第一种方法
第二种方法
原因在于,第一种方法在挪动元素时是从前向后挪,这就导致了第一个元素挪动后,第二个元素的位置已经被第一个元素占据,这之后挪动的元素将只是ai一个元素。
int j;
for( j = location; j < p->length; j++)
{
p->data[j+1] = p->data[j]; //location后的元素全是一个值
}
第一种方式的代码(错误)
知道了这些后,插入元素就变得简单了,以下是此操作的代码:
#define true 1
#define false 0
int insertlist(list_type* p, int new_node, int location)
{
int j;
if (p->length >= maxnum)
{
printf("\nthe list is full\n"); //错误1:表已经全满
return(false);
}
if (location < 1 || p->length + 1 < location)
{
printf("\nthe location is wrong\n"); //错误2:插入位置不能再插入元素
return(false);
}
location = location - 1;
for (j = p->length - 1; j >= location; j--)
{
p->data[j + 1] = p->data[j];
}
p->length++;
p->data[location] = new_node;
return(true);
注意:在每次循环插入元素之后,表的长度要加一。
5.删除顺序表中的元素
和插入元素一样,删除顺序表中的元素时也有两种方法,分别是:
①从最后一个元素到所删除的元素的位置逐个向前覆盖:
②从所删除元素位置的后一个元素逐个向前挪动覆盖:
插入操作和删除操作的错误方法犯的都是同一种错误,所以理解插入操作后,删除操作就变得很好理解了。先来看第一种操作的错误之处:最后一个元素在逐个向前覆盖时把所到之处元素的值全部变成了它自己,表中原来储存的数据全都失效了,所以不能采用这种方法。
第二种方法滴水不漏,自然而然的成立了(好耶),但是同样要注意,在每次删除元素后,表的长度要减一。
下面是它的代码:
int deletelist(mylist* p, int location)
{
int j;
if (p->length < 1)
{
printf("the list is empty"); //表空的判定
return(false);
}
if (location > p->length - 1||location<=0)
{
printf("the location is wrong"); //插入位置的错误
}
location = location - 1; //将location-1,使之变成下标值
for (j = location; j <= p->length - 1; j++)
{
p->data[j] = p->data[j + 1];
}
p->length--;
return(true); //删除成功
}
三、顺序表的练习题
1.合并两个线性递增表,合并后的表仍然是递增的合并两个线性递增表,合并后的表仍然是递增的。
分析:从每个表的第一个元素开始,挑出比较它们的大小,较大的继续保留,较小的元素放入新的合并表中,再向后推进一个元素,将元素逐个放入新表后,就得到了一个仍然递增的线性表。
注意:当一个表的全部节点都放在合并表里后,将另一个表的剩余节点放进合并表即可完成任务。
void merge(mylist*m,mylist*n,mylist*newlist)
{
int m_i,n_i,newlist_i;
m_i=0;
n_i=0;
newlist_i=0; //三个计数指针
while(m_i<m->length&&n_i<n->length)
{
if(m->data[m_i]<n->data[n_count])
{
newlist->data[newlist_i]=m->data[m_i];
m_i++;
}
else(m->data[n_i]<n->data[m_i])
{
newlist->data[newlist_i]=n->data[n_i];
n_i++;
} //比较大小并++,变成下一个位置
mewlist_i++;
}
while(m_i < m->length)
{
newlist->data[newlist_i] = m->data[m_i];
newlist_i = newlist_i+ 1;
m_i = m_i+ 1;
}
while(n_i < n->length)
{
newlist->data[newlist_i] = n->data[n_i];
n_i = n_i + 1;
newlist_i = newlist_i + 1; //如果有一个表变为空表,就把另一个表中的元素全部放入
}
2.首先创建一个顺序表:从键盘读入一组整数(长度小于等于20),按输入顺序放入顺序表,输入以-1结束(注意-1不放到顺序表内);将创建好的顺序表元素依次输出到屏幕上。
在已创建好的顺序表中插入一个元素:从键盘读入需插入的元素值和插入位置,调用插入函数完成插入操作;然后将顺序表元素依次输出到屏幕上。
在已创建好的顺序表中删除一个元素:从键盘读入欲删除的元素位置(序号),调用删除函数完成删除操作;然后将顺序表元素依次输出到屏幕上。
对一个元素有序(升序)排列的顺序表,任意给出一个数,要求插入到顺序表的正确位置,让插入后的顺序表也是有序(升序)排列的。
只需要把前面的基本操作稍微修改一下就可以。
整块全部代码如下:
#include<stdio.h>
#define maxnum 20
#define true 1
#define false 0
typedef struct list_type { //定义线性表
int data[maxnum];
int length;
}list_type;
void createlist(list_type* p)
{
int i, elem;
p->length = 0;
printf("please input the elems");
for (i = 0; i < maxnum; i++)
{
scanf("%d", &elem);
if (elem == -1) //题中-1条件的运用
break;
p->data[i] = elem;
p->length++;
}
}
void printlist(list_type* p)
{
int i;
printf("\nthe elems in the list are:\n");
if (p->length <= 0)
{
printf("no data!\n"); //错误处理:表为空
return;
}
for (i = 0; i < p->length; i++)
{
printf("%d\t", p->data[i]);
}
}
int insertlist(list_type* p, int new_node, int location)
{
int j;
if (p->length >= maxnum)
{
printf("\nthe list is full\n"); //错误处理:表满
return(false);
}
if (location < 1 || p->length + 1 < location)
{
printf("\nthe location is wrong\n");
return(false);
}
location = location - 1;
for (j = p->length - 1; j >= location; j--)
{
p->data[j + 1] = p->data[j];
}
p->length++;
p->data[location] = new_node;
return(true); //正确插入并返回true
}
int deletelist(list_type* p, int location)
{
int j;
if (p->length < 1)
{
printf("the list is empty");
return(false);
}
if (location > p->length - 1)
{
printf("the location is wrong"); //错误处理:插入位置错误
}
location = location - 1;
for (j = location; j <= p->length - 1; j++)
{
p->data[j] = p->data[j + 1];
}
p->length--;
return(true);
}
void insertsequ(list_type* p,int elem)
{
int location, i;
location = 0;
for (i = 0; i < p->length - 1; i++)
{
if (p->data[i] <= elem && p->data[i + 1] >= elem) //找出该元素的正确位置
{
location = i;
}
}
for (i = p->length - 1; i >= location; i--)
{
p->data[i + 1] = p->data[i];
}
p->data[location] = elem;
p->length++;
}
int main()
{
list_type list;
createlist(&list);
printlist(&list);
int i, data;
printf("\ninput the insert data\n");
scanf("%d", &data);
printf("\ninput the insert location\n");
scanf("%d", &i);
insertlist(&list, data, i);
printlist(&list);
int local;
printf("\ninput the delete location\n");
scanf("%d", &local);
deletelist(&list, local);
printlist(&list);
printf("\ninput a elem to finish the inserting orderly\n");
int elem;
scanf("%d", &elem);
insertsequ(&list, elem);
printlist(&list);
return 0;
}