单链表的创建部分
在创建结构体变量时 基本元素有两个部分 第一部分是你要存放数据的数据域 第二部分是你要存储的结构体指针变量next的指针域。
typedef struct dcode {
elemtype data;//数据域
struct dcode* next;//指针域
}dcode,*listhead;
其中的typedef 是一个较为常用的重命名方式 将我们这个结构体名字变为dcode 和*listhead,其实两者之间可以理解为是一样的性质。
我在下次使用时可以方便的编写代码,比如后续如果使用到结构体指针 我便可以直接用listhead,而用dcode来表示这个结构体,当然你也可以不用命名为*listhead,若想表示结构体指针decode* 都是一样的 这里只是为了后续方便使用........
单链表的初始化
这一部分其实我也有一些疑惑,如果我把主函数里的第二句放在初始化函数之中,就会出现变量l未定义的情况,我想这是因为函数他没办法传入一个未知大小的变量,所以在使用初始化函数之前我们可以为其开辟一片动态内存 利用官方头文件中的malloc函数 具体的使用方法可以参考以下链接malloc函数用法
//初始化结构体
void initlist(listhead l)
{
l->next = NULL;
}
int main()
{
listhead l;
l = (listhead)malloc(sizeof(dcode));
initlist(l);
}
创建单链表的两种方式
尾插法创建单链表
尾插法比较简单就是在新元素的后面继续插入,这里是需要两个结构体指针一个指针用来存放数据,可以称之为新结点,另一个指针用来指向当前指向的元素。直到我输入的值结束为止,这里我用了EOF来作为结束的一个标志,EOF的用法及相关可参考链接 因为scanf的返回值是int型,一般正常情况完成输入会返还1(有几个变量就返还几),当按下crtl z +回车之后就会跳出循环,但我使用的是vscode2019需要连续输入3次ctrl z+回车才可以。EOF的用法
bool backlinklist(listhead l )
{
int k;
listhead p, r=l;
while (scanf("%d", &k)!= EOF)
{
p = (listhead)malloc(sizeof(dcode));
p->data = k;
r->next = p;
r = p;
}
r->next = NULL;
return true;
}
头插法创建单链表
头插法顾名思义一直在头指针后面插入新的元素,实现的逻辑也非常简单:第一步创建一个新节点p 存入要传入的数据,然后将头指针的next传给新节点的next,再把头指针指向新节点就可以完成一次插入了。
//头插操作
bool frontlinklist(listhead l)
{
int k;
listhead p, r = l;
while (scanf("%d", &k) != EOF)
{
p = (listhead)malloc(sizeof(dcode));
p->data = k;
p->next = r->next;
r->next = p;
}
return true;
}
插入操作
顺序插入
顺序插入这里是依次按顺序插入操作类似于后插法建表找到要插入的位置并使用后插法即可完成插入。
bool orderinsertlist(listhead l)
{
int temp, position;
printf("请输入要插入的位置:");
scanf("%d", &position);
printf("\n请输入要插入的元素值:");
scanf("%d", &temp);
if (position < 0) return false;
dcode* p, * r;
p = l;
for (int i = 1; i < position; i++)
{
p = p->next;
}
if (p == NULL) return false;
r = (listhead)malloc(sizeof(dcode));
r->data = temp;
r->next = p->next;
p->next = r;
return true;
}
指定位置后插操作
首先将指定位置的next指针传入到一个新创建的节点的next中这样就可以使新节点链接到链表之中,接下来将要插入的元素值传入到新节点,最后在将指定位置的next指针指向新创建的节点即可。
//指定位置后插操作
bool backinsert(listhead l, listhead p,elemtype temp)
{
if (p == NULL) return false;
listhead s = (listhead)malloc(sizeof(dcode));//新的节点开辟空间
if (s == NULL) return false;//判断内存空间是否分配
//指针指向新节点,并把源节点的指针传输给新结点
s->next = l->next;
l->next = s;
s->data = temp;
return true;
}
指定位置前插操作
前插操作也可以看成是一种特殊的后插操作,他的实现逻辑是,同样先创造一个新的节点,接下来将原来指定位置结点中的值赋给一个中间变量,再将指定位置节点中的next值传给新节点中的next,这样新节点就链入列表,并把刚刚中间变量中的值赋给新节点的数据域,最后将原来节点的数据修改为要传入的数据,并把next指针指向新节点。
//指定位置的前插操作
bool frontinsert(listhead l, listhead p, elemtype temp)
{
if (p == NULL) return false;
listhead s = (listhead)malloc(sizeof(dcode));//新的节点开辟空间
if (s == NULL) return false;
//复制源节点到新节点,并把数值赋给源节点,再使源节点指向新节点;
s->next = l->next;
s->data = l->data;
l->data = temp;
l->next = s;
return true;
}
删除操作
指定节点删除
//指定节点删除
int deletelist(listhead l,listhead r)
{
int e;
if (r == NULL) return false;
e = r->data;
//理论上是删除r节点,但是我只要找到它的后继节点并将他们复制出去
//看似是是删除了源节点。实则是将下一级节点解除
listhead p = r->next;
r->data = r->next->data;
r->next = p->next;
free(p);
return e;
}
查找操作
按位查找
//按位查找
dcode* getelem(listhead l)
{
int k;
printf("你要查找哪一位?");
scanf("%d", &k);
listhead h = l;
if (k < 0) return NULL;
for (int i = 0; i < k; i++)
{
h = h->next;
}
if (h == NULL) return NULL;
printf(" %d", h->data);
return h;
}
按值查找
//按值查找
dcode* locateelem(listhead l)
{
int k;
printf("你要查找哪一个数?");
scanf("%d", &k);
listhead h = l;
while (h->data != k && h->next != NULL)
{
h = h->next;
}
return h;
}