链表概念
链表特点
(1)n个节点离散分配
(2)每一个节点之间通过指针相连
(3)每一个节点有一个前驱节点和一个后继节点
(4)首节点没有前驱节点,尾节点没有后继节点
struct link{
int data; //定义数据域
struct link *next; //定义指针域,存储直接后继的节点信息
};
链表定义
#include <stdio.h>
#include <stdlib.h>
struct Test
{
int a;
struct Test * next;
};
void printlink(struct Test * point)
{
while(point!=NULL){
printf("%d ",point->a);
point=point->next;
}
putchar('\n');
}
int main()
{
struct Test *head=NULL;
struct Test t1={1,NULL};
struct Test t2={2,NULL};
struct Test t3={3,NULL};
struct Test t4={4,NULL};
head = &t1;
t1.next=&t2;
t2.next=&t3;
t3.next=&t4;
printlink(head);
system("pause");
return 0;
}
数组和链表的区别?
数组和链表都属于线性表,数组的存储方式是顺序存储,它在内存中占用的地址空间是连续的,定义出来后空间大小是固定的,虽然读取效率较高但是不利于扩展(想要实现插入数据,修改数据相较于链表困难);链表的存储方式是链式结构,每一个结点的地址空间可以不连续,通过指针连接,每一个结点保存下一个结点的地址,相比于数组扩展方便,操作数据也更容易。
链表动态创建(增)
头插法
void insertfromhead(struct stu **head,struct stu *new)
{
if(*head == NULL){
*head = new;
}else{
new->next = *head;
*head = new;
}
}
或者
struct Test *insertFromHead(struct Test*head,struct Test *new)
{
if(head == NULL){
head = new;
}else{
new->next=head;
head=new;
}
return head;
}
用头插法动态创建链表
#include <stdio.h>
#include <stdlib.h>
struct stu
{
int data;
struct stu *next;
};
void insertfromhead(struct stu **head,struct stu *new)
{
if(*head == NULL){
*head = new;
}else{
new->next = *head;
*head = new;
}
}
void createLink(struct stu **head)
{
struct stu *new;
while(1){
new = (struct stu*)malloc(sizeof(struct stu));
printf("输入数据,(0代表结束):\n");
scanf("%d",&(new->data));
new->next = NULL;
if(new->data == 0){
return;
}
insertfromhead(head,new);
}
}
void printfLink(struct stu *head)
{
struct stu *p = head;
while(p != NULL){
printf("%d ",p->data);
p = p->next;
}
putchar('\n');
}
int main()
{
struct stu *head = NULL;
createLink(&head);
printfLink(head);
return 0;
}
尾插法
void insertfromtail(struct stu *head,struct stu *new)
{
if(head == NULL){
head = new;
}
while(head->next != NULL)
{
head = head->next;
}
head->next = new;
}
或者
struct Test *insertFromTail(struct Test*head,struct Test *new)
{
struct Test *p=head;
if(p==NULL){
head=new;
return head;
}
while(p->next!=NULL){
p=p->next;
}
p->next=new;
return head;
}
尾插法动态创建链表
#include <stdio.h>
#include <stdlib.h>
struct stu
{
int data;
struct stu *next;
};
void insertfromtail(struct stu **head,struct stu *new)
{
if((*head) == NULL){
(*head) = new;
}
while((*head)->next != NULL)
{
(*head) = (*head)->next;
}
(*head)->next = new;
}
void createLink(struct stu **head)
{
struct stu *new;
while(1){
new = (struct stu*)malloc(sizeof(struct stu));
printf("输入数据,(0代表结束):\n");
scanf("%d",&(new->data));
new->next = NULL;
if(new->data == 0){
return;
}
insertfromtail(head,new);
}
}
void printfLink(struct stu *head)
{
struct stu *p = head;
while(p != NULL){
printf("%d ",p->data);
p = p->next;
}
putchar('\n');
}
int main()
{
struct stu *head = NULL;
createLink(&head);
printfLink(head);
return 0;
}
删除链表的某个结点(删)
删除结点分两种情况:①是删除头结点;②是中间结点(包括尾结点)
/* 删除链表指定元素结点 */
struct Node *deleteNode(struct Node *head,int data){
struct Node *ptmp = head;
if(ptmp->data == data){ //删除头结点:直接让下一个结点成为头,并释放原来的head
head = ptmp -> next;
free(ptmp);
}else{ //删除中间结点:判断下一个结点,让此时的head指向next的next即可
while ( ptmp != NULL){
if( ptmp->next->data == data){ //特别注意:这里查询到了指定的data后,要return
struct Node *p = ptmp->next; //否则出现段错误:原因是下一个可能为NULL
ptmp->next = ptmp->next->next;
free(p);
return head;
}
ptmp = ptmp -> next;
}
}
return head;
}
修改链表的某个结点(改)
/* 修改指定元素 */
struct Node *updateNode(struct Node *head,int data,int newData){
struct Node *ptmp = head;
while(ptmp != NULL){
if(ptmp->data == data){
ptmp->data = newData;
}
ptmp = ptmp -> next;
}
return head;
}
链表的遍历(查)
/* 遍历 */
void traverLinkedList(struct Node *head){
struct Node *ptmp = head;
while(ptmp != NULL){
printf("%d ",ptmp->data);
ptmp = ptmp -> next;
}
}
如果要改变链表里的数据--就得传链表的地址
如果要改变链表头的地址-就得传链条头地址的地址