注意事项:
- 链表的函数中很容易出现备份当前指针的操作,注意使用时不要马虎
- 在使用未typedef的结构体时,前一定要加struct
- 其实所谓头插法的遍历就是一种栈 因其为“先进后出”
采用头插法插入,即在头节点后插入新来的节点
插入的方法为:让新来的节点有所指向,再打断原指向,即将头节点的next指向新来的节点
#include <stdio.h>
#include<stdlib.h>
//注意事项:
//1.在使用未typedef的结构体时,前一定要加struct
//2.其实所谓头插法的遍历就是一种栈 因其为“先进后出”
typedef struct _Node
{
int data;
struct _Node* next;
}Node;
//初始化链表即创建头指针以及头节点
Node* init_list(void)
{
Node* head = (Node*)malloc(sizeof(Node));
head->next = NULL;
return head;
}
//采用头插法插入,即在头节点后插入新来的节点
//插入的方法为:让新来的节点有所指向,再打断原指向,即将头节点的next指向新来的节点
void insert_list(Node* head,int data)
{
Node* cur = (Node*)malloc(sizeof(Node));
cur->data = data;
cur->next = head->next;
head->next = cur;
}
void traversal_list(Node* head)
{
Node* phead = head->next;
while (phead!=NULL)
{
printf("%d\n",phead->data);
phead = phead->next;
}
}
Node* search_list(Node* head,int data)
{
int flag = 1;
Node* phead = head->next;
while (phead!=NULL)
{
if(phead->data!=data)
phead = phead->next;
else {
flag = 0;
break;
}
}
if(0==flag)
{
printf("找到%d\n",data);
return phead;
}else {
printf("未找到%d\n",data);
return NULL;
}
}
Node* delete_list(Node* head,Node* p)
{
//删除节点
//判断此节点是否在链表中
int flag = 1;
Node* phead = head->next;
while (phead!=NULL)
{
if(phead!=p)
phead = phead->next;
else
{
flag = 0;
break;
}
}
if(0==flag)
{
printf("找到节点\n");
}else {
printf("错误:此节点不在本链表中无法删除\n");
return 0;
}
//1. 让它的前一个节点指向它后一个节点
//2. free这个节点
Node* p2 = p;
//先找到它前一个节点
Node* phead2 = head->next;
while (phead2->next!=p)
{
//注意:传递一级指针改变指针指向,不会改变外边的,因为是仅拷贝了这个地址
phead2 = phead2->next;
}
phead2->next = p2->next;
free(p2);
}
//排序分两种:
//1.交换数据
//2.交换节点,缺点:实现稍微复杂,但如果节点中除了data还有其他数据,通过data来实现其他内容的排序时显得尤为方便
void sort_list(Node* head)//按pop原理,交换数据
{
//按节点data的大小从小到大排序
//原理:设两个相邻的节点
// 这两个节点就是类比数组冒泡排序中的i,和i+1
//冒泡的原理即:比较两个相邻数据,一次遍历将最后放到末尾
// 二次遍历将次最值放到末尾
int len = len_list(head);
//关于冒泡排序的原理:
//1. 外重循环的i告诉内重循环,j走到哪里停止
//也就是说:第一次j走到倒数第二个数
// 第二次j走到倒数第三个数
//....最后j=0一步不走即结束
int i =0;
int j = 0;
for(i = 0;i<len-1;i++)
{
Node* p1 = head->next;
Node* p2 = p1->next;
for(j = 0;j<len-1-i;j++)
{
if(p1->data>p2->data)
{
p1->data ^= p2->data;
p2->data ^= p1->data;
p1->data ^= p2->data;
}
p1 = p1->next;
p2 = p1->next;
}
}
}
//思想:从头节点将链表一分为2,这步的目的是为了将头节点的next再度置空以便头插法
// 逐个将链表头再以头插法插入链表,即把最后进来的最先再进入链表
void reversal_list(Node* head)
{
Node* phead = head->next;
head->next = NULL;
Node* phead2;
while (phead!=NULL)
{
//备份phead的下一个节点
phead2 = phead->next;
//令新来的节点有所指向
phead->next =head->next;
//令头节点指向它
head->next = phead;
phead =phead2;
}
}
int len_list(Node* head)
{
int len = 0;
Node* phead = head->next;
while (phead!=NULL)
{
printf("%d\n",phead->data);
phead = phead->next;
len++;
}
return len;
}
//测试
int main(int argc, char *argv[])
{
Node* head = init_list();
insert_list(head,1);
insert_list(head,2);
insert_list(head,3);
insert_list(head,4);
insert_list(head,666);
insert_list(head,555);
traversal_list(head);
Node* p = search_list(head,2);
delete_list(head,p);
traversal_list(head);
reversal_list(head);
traversal_list(head);
int a = len_list(head);
printf("a = %d\n",a);
sort_list(head);
traversal_list(head);
printf("Hello World!\n");
return 0;
}