7.数据结构1.0
定义:研究数据存储,数据处理的学科
线性表
定义:一组由n个相同数据类型的数据元素组成的有限序列
特性:(1)、除第一个元素外,每一个元素有且仅有一个前驱节点
(2)、除最后一个元素外,每一个元素有且只有一个后继节点
线性表分类:顺序表、链表、栈、队列、字符串……
线性表在逻辑上是线性表,但是在物理结构上并不一定是连续的;在物理上储存的时候一般以数组或者链表的形式存在;
1、顺序表
顺序表:在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中。
特点:随机存取,插入和删除比较麻烦
#define Max 100
#define ElementType int
struct Array
{
ElementType array[Max];//初始化数组,申请内存
int len;//设置数组长度
}
//遍历输出数组
void travel(struct Array *a)
{
for(int i=0;i<a->len;i++)
{
printf("%d ",a->array[i]);
}
printf("\n");
}
1、顺序表的操作:插入
【1】、头插法
void InsertHead(struct Array *a,ElementType element)
{
if(a->len >= max)//判断数组是否已满
{
printf("InsertHead out of range!\n");//已满,打印输出超出范围,返回;
return;
}
for(int i=a->len-1;i>=0;i--)
{
a->array[i+1] = a->array[i];//将当前从第一位开始的所有的数值向后移动一格
}
a->array[0] = element;//第一个数进行赋于要插入的值
a->len++;//数组长度+1
}
//测试接口
int main()
{
struct Array a;
a.len=0;
for(int i=0;i<5;i++)
{
InsertHead(&a,i+1);
}
Travel(&a);
return 0;
}//输出5 4 3 2 1
【2】、尾插法
void InsertTail(struct Array *a,ElementType element)
{
if(a->len >=Max)//判断数组是否已满
{
printf("InsertTail out of range!\n");//已满,打印输出超出范围,返回;
return;
}
a->array[a->len] = element;//数组最后一位后面直接插入要插入的元素
a->len++;//数组长度+1
}
//测试端口
int main()
{
struct Array a;
a.len = 0;
for (int i = 0; i < 5; i++)
{
InsertTail(&a,i+1);
}
travel(&a);
return 0;
}// 1 2 3 4 5
【3】、插入相应的位置
void InsertIndex(struct Array *a,ElementType element,int index)
{
if(index<0 || index>len)//判断要插入的位置是否合法
{
printf("InsertIndex invalid place!\n");//不合法,打印输出插入位置不合法,返回;
return;
}
if(a->len>=Max)//判断数组是否已满
{
printf("InsertIndex out of range!\n");//已满,打印输出超出范围,返回;
return;
}
for(int i=a->len;i>index;i--)//遍历找到要插入的位置,从尾部开始找
{
a->array[i]=a->array[i-1];//将每一个元素向后移一位
}
a->array[index]=element;//当前位置插入要插入的值
a->len++;//数组长度+1
}
//测试端口
int main()
{
struct Arrray a;
a.len=0;
for (int i = 0; i < 5; i++)
{
InsertHead(&a,i+1);
}
InsertIndex(&a,100,2);
InsertIndex(&a,100,2);
Travel(&a);
return 0;
}//输出 5 4 100 100 3 2 1
2、顺序表操作:删除
【1】、按位删除
void RemoveByIndex(struct array *a,int index)
{
if(index<0 || index >= a->len)//判断删除位置是否合法
{
printf("removeIndex invalid place!\n");//非法,打印输出删除位置不合法,返回;
return;
}
for(int i=index;i<a->len;i++)
{
a->array[i]=a->array[i+1];//从删除的位置开始到数组结束每一位元素向前移动一位
}
a->len--;//数组长度-1
}
//测试端口
int main()
{
struct array a;
a.len=0;
for (int i = 0; i < 5; i++)
{
InsertHead(&a,i+1);
}
RemoveByIndex(&a,2);
travel(&a);
return 0;
}// 5 4 2 1
【2】、按值删除
void RemoveByElement(struct array *a,ElementType element)
{
for(int i=0;i<a->len;i++)//从头开始遍历找到要删除的值
{
if(a->array[i] == element)//判断当前位置的值与要删除的值是否相同
{
RemoveByIndex(a,i);//删除当前位置的值
i--;//因为删除导致后一位向前移动,但是原本后一位的值还未判断,所以进行i--,继续判断当前位置
}
}
}
//测试端口
int main()
{
struct Array a;
a.len = 0;
for (int i = 0; i < 5; i++)
{
InsertHead(&a,i+1);
}
RemoveByElement(&a,2);
Travel(&a);
return 0;
}//输出 5 4 3 1
3、顺序表操作:查找
【1】、按值查找
注意返回的是一个数组,用来存储返回的下标,如果用普通指针,存在局部变量,局部变量结束就结束访问,所以得将数组存在堆上;在主函数输出存放的下标的数组时,需要遍历数组,但是我们不知道存放数组下标的大小,所以需要设置一个标志位用来存放数组的长度。
方法一:在数组的第一位存放数组的长度
int* FindByElement(struct array* a,ElementType element)
{
int *findVerctor = (int *)malloc(sizeof(int)*(a->len+1));//申请一个数组用来存储返回的下标
if(findVertor == NULL)//判断堆上申请的空间是否成功
{
printf("malloc error!\n");//申请失败,打印错误信息,返回空指针
return NULL;
}
int count=0;//设置一个计数器
for(int i=0;i<a->len;i++)//遍历查找从0开始直到数组结束
{
if(a->array[i]==element)//判断当前位置值与要查找的值是否相同
{
count++;//计数器+1
findVerctor[count]=i;//第一位存储新数组长度,所以要先进行count++,然后将当前位置下标存入新数组
}
}
findVerctor[0]=count;//第一位存入新数组的长度
return findVerctor;
}
//测试端口
int main()
{
struct Array a;
a.len = 0;
for (int i = 0; i < 5; i++)
{
InsertHead(&a,i+1);
}
InsertIndex(&a,100,2);
InsertIndex(&a,100,2);
int *findVector = FindByElement(&a,100);//设置一个指针用来接收FindByElement返回的新数组;
if(findVector!=NULL)
{
int length=findVector[0];
for(int i=1;i<=length;i++)
{
printf("find NO.%d index : %d \n",i,findVector[i]);
}
free(findVector);
}
return 0;
}//find NO.2 index : 100
//find NO.3 index : 100
方法二:在数组的最后一位的后面一位设置为-1代表结束
int* FindByElemet(Larray *a,ElementType element)
{
int *findVerctor =(int *)malloc(sizeof(int)*(a->len+1));//申请一个数组用来存储返回的下标
if(findVerctor == NULL)//判断堆上申请的空间是否成功
{
printf("FindVerctor malloc error!\n");//申请失败,打印错误信息,返回空指针
return NULL;
}
int count=0;//设置一个计数器
for(int i=0;i<a->len;i++)//遍历查找从0开始直到数组结束
{
if(a->array[i]==element)//判断当前位置值与要查找的值是否相同
{
findVerctor[count]=i;//当前位置下标存入新数组,因为这个从0开始存入新数组,所以count后进行++
count++;//计数器+1
}
}
findVerctor[count]=-1;//设置结束标志位
return findVerctor;
}
int main()
{
struct Array a;
a.len = 0;
for (int i = 0; i < 5; i++)
{
InsertHead(&a,i+1);
}
InsertIndex(&a,100,2);
InsertIndex(&a,100,2);
int *findVector = FindByElement(&a,100);
if(findVector!=NULL)
{
int *temp=findVerctor;
while(*temp!=-1)
{
printf("find index : %d \n",*temp);
temp++;
}
free(findVector);
}
return 0;
}//find NO.2 index : 100
//find NO.3 index : 100
【2】、按位查找
ElementType* FindByIndex(struct Array *a,int index)
{
if(index<0 || index>=a->len)
{
printf("FindByIndex invalid place!\n");
return NULL;
}
return &a->array[index];
}
4、顺序表操作:修改
【1】、按位修改
void SetValueByIndex(struct Array *a,int index,ElementType element)
{
if(index<0 || index >= a->len)
{
printf("SetValueByIndex invalid place!\n");
return;
}
a->array[index] = element;
}
//端口测试
int main()
{
struct Array a;
a.len=0;
for (int i = 0; i < 5; i++)
{
InsertHead(&a,i+1);
}
SetValueByIndex(&a,1,90);
Travel(&a);
return 0;
}//5 90 3 2 1
【2】、按值修改
void SetValueByElement(struct Array* a,ElementType OldElement,ElementType NewElement)
{
for(int i=0;i<a->len;i++)
{
if(s->array[i]==OldElement)
{
a->array[i]=NewElement;
}
}
}
//测试端口
int main()
{
struct Array a;
a.len=0;
for (int i = 0; i < 5; i++)
{
InsertHead(&a,i+1);
}
SetValueByElement(&a,1,90);
Travel(&a);
return 0;
}//5 4 3 2 90
5、顺序表的其他操作
【1】、求交集:查找两个串相同的元素并返回
struct Array* FindIntersection(struct Array *a1,atruct Array *a2)
{
struct Array *intersection=(struct Array*)malloc(sizeof(struct Array));
if(intersection == NULL)
{
printf("findInterSection malloc error!\n");
return NULL;
}
intersection->len = 0;
if(a1->len==0 || a2->len==0)
{
return NULL;
}
for(int i=0;i<a1->len;i++)
{
for(int j=0;j<a2->len;j++)
{
if(a1->array[i]==a2->array[j])
{
int flag=0;
for(int k=0;k<intersection->len;k++)
{
if(intesection->array[k]==a1->array[i])
{
flag=1;
}
}
if(flag==0)
{
InsertTail(intersection,a1->array[i]);
}
}
}
}
return intersection;
}
【2】、求并集
算法思想:分别存储两个数列到同一个数组,然后对新数组去重
void Dedupliation(struct Array *array)
{
Quick_Sort(array->array,0,array->len-1);
for(int i=1;i<array->len;i++)
{
if(array->array[i]==array->array[i-1])
{
RemoveByIndex(array,i);
i--;
}
}
}
struct Array* FindUnionSet(struct Array *a1,atruct Array *a2)
{
struct Array *UnionSet=(struct Array*)malloc(sizeof(struct Array));
if(UnionSet == NULL)
{
printf("findUnionSet malloc error!\n");
return NULL;
}
UnionSet->len = 0;
for(int i=0;i<a1->len;i++)
{
InsertTail(UnionSet,a1->array[i]);
}
for(int j=0;j<a2->len;j++)
{
InsertTail(UnionSet,a2->array[j]);
}
Dedupliation(UnionSet);
return UnionSet;
}
//测试端口
int main()
{
Larray a1;
a1.len=0;
InsertTail(&a1,1);
InsertTail(&a1,2);
InsertTail(&a1,3);
InsertTail(&a1,2);
Larray a2;
a2.len=0;
InsertTail(&a2,3);
InsertTail(&a2,4);
InsertTail(&a2,5);
struct Array* unionset= FindUnionSet(&a1,&a2);
if(unionset!=NULL)
{
Travel(unionset);
}
free(unionset->array);
return 0;
}//输出1 2 3 4 5
【2】、将两个数组合并成一个新的有序数组
算法思想:如果是两个无序的数组,先分别对俩个数组排序,然后设置两个下标 i
和 j
;分别遍历两个数组,当 i
所指向的数组值小于 j
所指向的数组值,则储存 i
指向的值到新的数组中,反之则存储 j
所指向的值,直到两个数列中短的那个数组全部存完,此时继续存入长的那个数列的剩下值,合并到同一个数组。
struct Array* MergeArray(struct Array *a1,atruct Array *a2)
{
Quick_Sort(a1->array,0,a1->len-1);
Quick_Sort(a2->array,0,a2->len-1);
struct Array *merge=(struct Array*)malloc(sizeof(struct Array));
if(merge == NULL)
{
printf("MergeArray malloc error!\n");
return NULL;
}
merge->len = 0;
int i=0,j=0;
while(i<a1->len && j<a2->len)
{
if(a1->array[i]<a2->array[j])
{
InsertTail(merge,a1->array[i]);
i++
}
else
{
InsertTail(merge,a2->array[j]);
j++;
}
}
while(i<a1->len)
{
InsertTail(merge,a1->array[i]);
i++
}
while(j<a2->len)
{
InsertTail(merge,a2->array[j]);
j++;
}
return merge;
}
//测试端口
int main()
{
Larray a1;
a1.len=0;
InsertTail(&a1,7);
InsertTail(&a1,5);
InsertTail(&a1,3);
InsertTail(&a1,1);
Larray a2;
a2.len=0;
InsertTail(&a2,6);
InsertTail(&a2,4);
InsertTail(&a2,2);
struct Array* unionarray=(struct Array*)malloc(sizeof(struct Array));
unionarray=MergeArray(&a1,&a2);
Travel(unionarray);
return 0;
}//1 2 3 4 5 6 7
2、栈(数组型)
1、栈的定义:只允许在一端进行插入或者删除操作的线性表
栈顶(Top):线性表允许进行插入删除的那一端。
栈底(Bottom):固定的,不允许进行插入和删除的另一端。
空栈:不含任何元素的空表。
//栈的顺序存储结构
#define ElementType int
#define Max 10
struct Stack
{
ElementType stack[Max];
int len;
};
2、特点:先进后出(Last in First Out)
3、栈的操作:
【1】、入栈push
void Push(struct Stack *s,ElementType element)
{
if(s->len >= Max)
{
printf("Stack is Full!\n");
return;
}
s->stack[s->len] = element;
s->len++;
}
【2】、出栈pop
ElementType* Pop(struct Stack *s)
{
if(s->len==0)
{
printf("Stack is empty!\n");
return NULL;
}
s->len--;
return &s->stack[s->len];
}
//测试端口
int main()
{
struct Stack s;
s.len=0;
for(int i=0;i<10;i++)
{
Push(&s,i+1);
}
while(s.len!=0)
{
printf("%d ",*Pop(&s));
}
printf("\n");
return 0;
}
- 课堂测试:栈的应用:进制转换
#inlcude<stdio.h>
#define ElementType int
#define Max 10
struct Stack
{
ElementType stack[Max];
int len;
};
int main()
{
int num=0;
printf("Please input your number:");
scanf("%d",&num);
int n=0;
printf("Please input a system num :");
scanf("%d",&n);
if(n==16)
{
printf("0x");
}
while(num!=0)
{
int temp=num%n;
if(temp<=9)
{
temp = temp+'0';
}
else
{
temp = temp-10 + 'A';
}
Push(&s,temp);
num = num / n;
}
while(s.len !=0)
{
printf("%c",*Pop(&s));
}
printf("\n");
return 0;
}