1.线性表的顺序表示
事件复杂度是要忽略高阶项系数和低阶项,上面的答案是O(n)
动态分配的数组仍属于顺序存储结构
什么是动态分配?
- int p=(int )malloc(sizeof(int)*10);申请了一个空间,用数组的方式去做。
所有数据结构的4种操作:
- 增删改查
什么是单步调试?
- 每执行一步,数据的变化是怎么样的,是否符合自己的预期。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef int ELemType;
typedef struct LNode{
ELemType data;
struct LNode* next;//指向下一个结点
}LNode,*LinkList;
//头插法
//和表尾无关,只动表头,所以变化L,初始化时表头就是表尾
//先给表头申请空间,在判断插入的数据是否符合条件,符合则申请下一个链表空间
//先让s指向L指向的元素(初始时为Null),(因为L不能同时指向两个结点,所以不先连接L和s),再让L指向s
// 如果先让L指向s的话,那就以前的p的next就失效了
//输入数据,执行循环
void CreateList1(LinkList &L) {
LNode* s;
int x;
L = (LinkList)malloc(sizeof(LNode));//带头结点的链表
L->next = NULL;//L->data里面没有放东西
scanf("%d", &x);//从标准输入读取数据
//3 4 5 6 7 9999
while (x != 9999) {
//如果输出的不是9999,,则添加元素申请一个新空间给s,强制类型转换
s = (LNode*)malloc(sizeof(LNode));
s->data = x;//吧读取到的值给新空间中的data成员
s->next = L->next;//让新结点的next指针指向链表的第一个元素(第一个放我们数据的元素)
L->next = s;//让s作为第一个元素
//第一个元素不是头结点,因为头结点什么也没存
scanf("%d", &x);//从标准输入读取数据
}
}
//尾插法
// 不管表头的事,初始化时表头就是表尾,前面不动,只动表尾
//先给表头申请空间,在判断插入的数据是否符合条件,符合则申请下一个链表空间
//因为r是表尾,所以next为NULL
//定义一个结构体s存要插入的数据,复制表头的地址,做表尾,用于确定尾部的位置(确定是否超出范围等等)
//进入循环后,给s赋值和下一个结点地址,r的next由Null指向s,s成为表尾
LinkList CreateList2(LinkList &L) {
int x;
L = (LNode*)malloc(sizeof(LNode));//申请一个带头结点的链表
LNode* s, * r = L;//结构体指针,也可以写成LinkList s,r=L;r代表表尾结点,r指向表位尾部
//创建r是为了让r始终指向尾部,否则下次插入就要从开头遍历到尾部
scanf("%d",&x);
while (x != 9999) {
s = (LinkList)malloc(sizeof(LNode));
s->data = x;
r->next = s;//让尾部结点指向新结点
r = s;//r指向是表尾结点
scanf("%d",&x);
}
r->next = NULL;//让尾指针的next指针赋值为NULL
return L;
}
//打印链表
//不改变值,不用加引用,如果加引用的话最后的结果为Null
//如果不想改变值且加了引用,可以把形参给另一个变量来操作另一个变量
//如void PrintList(LinkList &a) LinkList L=a;
void PrintList(LinkList L) {
//要不要加引用,就是看是不是在子函数中要去改变主函数对应的变量,要改就要加。
L = L->next;
while (L != NULL) {//NULL是代表一张空的藏宝图,next是宝藏
printf("%3d\n",L->data);//打印当前结点数据
L = L->next;//指向下一个结点
}
}
//按序列查找
//先定义一个序号,代表链表当前位置,在定义链表p表示当前所在链表
//判断序列是否合法
// 进入循环遍历,判断链表是否为空,且当前位置不能大于要查的序列
// 挨个遍历
LinkList GetElem(LNode* L, int i) {
int j = 1;//从第一个有数据的结点开始,因为下一步是L->next,所以j=1
LinkList p = L->next;//让p指向下一个结点
if (0 == i)
return L;//i是0就返回头结点
if (i < 1)
return NULL;
while (p&&j<i) {
p = p->next;//让p指向下一个结点
j++;
}
return p;
}
//按值查找
LinkList LocateElem(LinkList L,ELemType e) {
LinkList p = L->next;
while (p != NULL&&p->data!=e) {
p = p->next;
}
return p;
}
//往第i个位置插入元素
bool ListFrontInsert(LinkList L,int i,ELemType e) {
LinkList p = GetElem(L,i-1);//拿到要插入位置的前一个结点的地址值
if (NULL == p)
return false;
LinkList s = (LinkList)malloc(sizeof(LNode));//给新结点申请空间
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
//删除第i个位置的元素
// 要找到前一个结点
//需要两个链表,一个是结点前的,一个是结点后的,因为删除后要连接起来
//判断前一个结点是否为空结点
// 让前一个结点的next指向要删除结点的next
// 释放当前要删除的结点,避免空指针异常
//没有用引用,是因为没有改变L的值
bool ListDelete(LinkList L,int i){
LinkList p = GetElem(L, i - 1 );
if (NULL == p) //判断p,因为要访问p->next如果为Null下面的程序就会崩溃
return false;
LinkList q = p->next;
if (q == NULL)
return false;
p->next = q-> next;
free(q);
q = NULL;//为了避免野指针
return true;
}
int main() {
LinkList L;//链表头,是结构体指针类型
LinkList search;
CreateList2(L);//输入数据可以为3 4 5 6 7 9999(输入9999代表循环结束)
PrintList(L);
search=GetElem(L, 2);//查找链表第二个位置的元素值
if (search != NULL) {
printf("按序号查找成功\n");
printf("%d\n",search->data);
}
search = LocateElem(L,6);//按值查询
if (search != NULL) {
printf("按值查找成功:%d\n", search->data);
}
ListFrontInsert(L,2,99);
PrintList(L);
//ListDelete(L, 4);
//PrintList(L);
return 0;
}