关于课程设计中链表的操作
链表的概念
首先我们必须了解什么是链表,链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
第 0 个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量。以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学生姓名,学生号码,学生成绩 和爱好 等。另一个域为指针域,存放下一结点的首地址。链表中的每一个结点都是同一种结构类型。
建立一个链表
首先我们必须先建立一个链表,我们常见的创建链表的方法有两个,分别为头插法和尾插法。我们了解到一般我们最开始学习链表的时候,我们基本上创建的链表都是具有头结点的链表,所谓头结点就是不存数据只存下一个结点的首地址的结点。
头插法
所谓头插法,就是将每一个结点插入到头结点的后边,需要注意的是我们将新结点插入到头结点之前,为了防止数据的丢失,必须先将原来在头结点后边的数据的首地址放入新结点的指针域中。
代码如下:
LinkList CreateList_Head(LinkList headlish)
{
LinkList s;int x;
headlish = (LNode*)malloc(sizeof(LNode)); //创建头结点
headlish -> next = NULL;
scanf("%d",&x);
while(x!=9999){
s = (LNode*)malloc(sizeof(LNode));
s -> Data = x;
s -> Next = L -> Next;
L -> Next = s; //插入结点
scanf("%d", &x);
}
return headlish;
}
尾插法
所谓尾插法,顾名思义就是将新结点放在每个尾结点的后边,一般在运用这个方法的时候我都会实现声明两个指针变量,一个头指针,一个尾指针。
代码如下:
struct shu *head = NULL;
struct shu *tail = NULL;
然后尾指针指向最后一个结点我们的新结点只需要放在尾指针后边就行了。
代码如下:
LinkList CreateList_Tail(LinkList L)
{
int n;
scanf("%d", &n);
while (n != 9999)
{
struct shu *temp;
temp = (struct shu *)malloc(sizeof(struct shu));
scanf("%d", &temp->zhi);
temp -> next = NULL;
if (head == NULL)
{
head = temp;
tail = temp;
}
else
{
tail -> next = temp;
tail = temp;
}
}
}
链表的基本操作
增
一般当我们平时或者写课设的时候在链表已经创建好的情况下增加新结点时,我们需要有一个数据去找位置,比如按照学生的成绩,学生的学号等等之类的。当我们找到那个位置的时候,我们需要把原本在这个位置的结点的首地址放入新结点的指针域,将链表串联起来。
代码如下:
void insert()
{
LinkList *p, *q;
LinkList *temp;
temp = (player *)malloc(sizeof(player));
p = head;
temp->next = NULL;
scanf("%d", &temp->id);
if (head == NULL)
{
head = temp;
}
else
{
while (strcmp(p->id, temp ->id) < 0 && p->next != NULL)
{
q = p;
p = p->next;
}
}
if (strcmp(p->id, temp ->id) > 0)
{
if (p == head)
{
temp->next = head;
head = temp;
}
else
{
q->next = temp;
temp->next = p;
//printf("!");
}
}
else
{
p->next = temp;
}
}
return;
}
删
删除的时候我们必须找到要删除的数据,然后将它指针域中下一个结点的首地址放入前一个结点的指针域使前后连接起来就行了。
代码如下:
struct ListNode* deleteNode(struct ListNode* head, int val){
struct ListNode * p=head;
if (head->val == val)
{
return head->next;
}
while (p->next)
{
struct ListNode *temp = NULL;
temp = (struct ListNode *)malloc(sizeof(struct ListNode));
if (p->next->val == val)
{
temp = p -> next;
p -> next = temp -> next;
free(temp);
}
else
p = p -> next;
}
return head;
}
查
在我的理解中,查找是链表操作的基础,一般在我们的课程设计中,都会按照一些数据去查找,比如说在学生管理系统中,我要找张三同学,我们就需要按照张三同学的姓名字符串去在每一个结点的数据域中比较,直到找到或者遍历完链表。
代码如下:
player *search(player *head) {
char st[20];
int i;
printf("请输入你想要查找的球衣号码或者姓名按'*'退出\n");
scanf("%s", st);
getchar();
if (st[0] == '*') {
return NULL;
}
player *temp = head;
if (head == NULL)
{
printf("未录入信息!");
return NULL;
}
else
{
while (temp)
{
if (!strcmp(temp->number, st) || !strcmp(temp->name, st))
break;
temp = temp->next; //temp后移
}
}
if (temp == NULL)
{
printf("没有找到相关信息!");
goto Repeat; //返回Repeat处
}
else
{
printf("查找成功!该球员信息如下:\n");
printf("球员编号:%s\n", temp->id);
printf("球员球衣号码:%s\n", temp->number);
printf("球员名字:%s\n", temp->name);
printf("球员年龄:%d\n", temp->age);
printf("球员的场上位置:%s\n", temp->place);
printf("球员赛季场均得分:%.1lf\n", temp->score);
}
printf("请确认信息是否有误\n1.正确\t2.错误\n");
scanf("%d", &i);
fflush(stdin);
if (i == 1)
printf("已找到该球员信息!\n");
return temp;
}
为了让大家更加理解,这个代码是我写课程设计时候的查找函数,可以看到我是通过查找球星的名字或者球衣号码来找球员的,我们通过字符串比较函数来找,如果找到了我们就将其中的数据打印出来,如果还没找到且链表还没遍历完我们就继续遍历,直到找到或者遍历完毕。
改
修改结点,我们必须先找到结点的位置,因为只要找到了结点的位置我们才能去修改他的数据域。下面放上我在写课程设计时的代码:
void change()
{
system("cls");
char st[20];
int num;
player *temp = search(head); //进入查找函数
if (temp == NULL)
{
printf("未找到想要修改的位置:");
} else
{
int i;
Repeat:
printf("想要修改的内容:(按0退出!)\n");
printf("1.球员编号\t2.球员球衣号码\t3.球员姓名\t4.球员年龄\t5.球员场上位置\t6.球员赛季场均得分\n");
scanf("%d", &i);
if (i < 1 || i > 6) {
printf("选择无效,请重新输入:\n");
fflush(stdin);
goto Repeat;
}
switch (i) {
case 1:
printf("请输入正确的编号:");
scanf("%s", temp->id);
break;
case 2:
printf("请输入正确的球衣号码:");
scanf("%s", temp->number);
break;
case 3:
printf("请输入正确的球员姓名:");
scanf("%s", temp->name);
break;
case 4:
printf("请输入正确的球员年龄:");
scanf("%d", &temp->age);
break;
case 5:
printf("请输入球员的正确的场上位置:");
scanf("%s", temp->place);
break;
case 6:
printf("请输入正确的球员赛季场均得分:");
scanf("%lf", &temp->score);
break;
case 0:
break;
}
getchar();
printf("修改后的球员信息为:\n");
printf("球员编号:%s\n", temp->id);
printf("球员球衣号码:%s\n", temp->number);
printf("球员名字:%s\n", temp->name);
printf("球员年龄:%d\n", temp->age);
printf("球员的场上位置:%s\n", temp->place);
printf("球员赛季场均得分:%.1lf\n", temp->score);
printf("请问是否修改成功?\n");
printf("1.成功\t2.失败\n");
scanf("%d", &num);
fflush(stdin);
if (num == 1) {
printf("您已确认,修改完成!\n");
system("pause");
}
}
return;
}
因为要先找到那个结点,所以我们先进入查找函数,查找函数的返回值就是那个要修改的结点的首地址,所以我们找到了之后就可以修改数据域中的数据了,所以我前边说查找是每个操作的基础。
希望本周分享的关于课程设计中链表的操作对各位要写课程设计的同学有帮助!