开始学习数据结构,虽然部分之前C都学过,还是总结一下。内容比较多
直接看例子
list.h //头文件
#include<stdlib.h>
#include<stdio.h>
typedef struct _Node //节点定义
{
int data; //数据域
struct Node * next; //指针域
}Node;
Node * creatList(); //建立链表
void insertList(Node* head,int data); //插入
void traverseList(Node * head); //遍历
int lenList(Node * head); //求表长
Node* searchList(Node* head,int find);//查找
void deleteList(Node * head, Node * pfind); //删除
void popSortList(Node* head); //排序
void reverseList(Node* head); //反转
void destoryList(Node * head); //销毁
list.c //实现,重点!
#include"list.h" //自包含
//带有头节点的链表
//首先说明:head指针 指向一个 头节点 ,头节点是存放了首节点的地址。首节点才是我们需要的链表开始。
//所以我们需要的链表一开始的地址是 head->next;
//以下入参性检查省略
Node * creatList() //建立空链表
{
Node* head=(Node*)malloc(sizeof(Node));
head->next=NULL;
return head;
}
void insertList(Node* head,int data) //插入(头插法)
{
Node* cur=(Node*)malloc(sizeof(Node));
cur->data=data;
cur->next=head->next; //让先来的节点先有所可依
head->next=cur; //再打断原来的关系
}
void traverseList(Node * head) //遍历
{
head=head->next;
while(head)
{
printf("%2d\t",head->data);
head=head->next;
}
printf("\n");
}
int lenList(Node * head) //求表长
{
int count=0;
head=head->next;
while(head)
{
count++;
head=head->next;
}
return count;
}
Node* searchList(Node* head,int find)//查找
{
head=head->next;
while(head)
{
if(head->data == find)
break ;
else
head=head->next;
}
return head; //这里把 if 和 else 两个return head和NULL合并了,没有找到自然为空
}
void deleteList(Node * head, Node * pfind) //删除某个节点
{
if(pfind->next == NULL) //方法一
{
while(head->next != pfind) //方法一,实际上还是完成了一次遍历
head=head->next;
head->next=pfind->next;
free(pfind);
}
else //方法二
{
Node * t = pfind->next; //要删除节点的下一个节点
pfind->data = t->data; //让要删除的节点的下一个节点的值 赋给要删除的节点
//这样就是需要删除 t,这个方法就是需要pfind->next 不为空即可
pfind->next=t->next;
free(t);
}
}
void popSortList(Node* head) //排序
{
#if 0
int len=lenList(head);
for(int i=0 ; i< len-1 ; i++) //冒泡法,由于这里冒泡是相邻之间比较,所以只需要到倒数第二个数就可以
{ //这样就是最后两个数相比
Node*p=head->next; //每次都要从头开始
Node*q=p->next;
for(int j=0;j<len-1-i;j++) //比的次数,就是从看比较换位后,剩多少需要交换,所以减 i
{
if(p->data>q->data)
{
p->data ^=q->data; //无参交换
q->data ^=p->data;
p->data ^=q->data;
}
p=p->next;
q=p->next;
}
}
#endif
//不交换值,改变链表的链接顺序,本质也是进行排序,可看下图,可能第一次较复杂,结合图一起看就好多了
Node *p,*q,*pre;
int len=lenList(head);
for(int i=0 ; i< len-1 ; i++)
{
pre=head; //head可能还要用,所以不改变head,用一个替身
p=head->next;
q=p->next;
for(int j=0;j<len-1-i;j++)
{
if(p->data>q->data)
{
pre->next=q; //这里主要是看图中,把链表进行变直
p->next=q->next; //再这里先进行第一步,第二步不能先打断 q->next=p;
q->next=p; //q->next一打断,q 原来的 next 则没有连接找不到,则内存泄露
pre=q; //在这里的结果实际上p q的顺序变成q p了,这样逻辑与之前不同,需要再交换回来
q=p->next; //这里直接把 pre移到 q的位置上,q变成下一位,直接进行移到下一位,用continue跳过后面的移位
continue;
}
pre=pre->next;
p=p->next;
q=p->next;
}
}
}
void reverseList(Node* head) //反转,本质也是头插法,链表头插到另一个链表
{
Node * h=head->next;
head->next=NULL; //打散头节点,让它变成空链表,上面行的 h 也就是接手后面的节点
Node*t;
while(h)
{
t=h->next; //跟下面的销毁释放一样,若不为空,找一个替身,先指向下一个
h->next=head->next; //头插法
head->next=h;
h=t; //指向的下一个继续进行上面的操作,继续头插,插入就在上面节点的前面了
}
}
void destoryList(Node * head) //销毁释放
{
Node *t;
while(head)
{
t=head->next; //若不为空,找一个替身,先指向下一个
free(head); //再销毁本身,否则无法一个接一个销毁
head=t;
}
}
main函数
#include <stdio.h>
#include"list.h"
#include<time.h>
#include<stdlib.h>
int main()
{
Node * head=creatList();
traverseList(head);
srand(time(NULL)); //产生随机数
for(int i=0;i<10;i++)
{
insertList(head,rand()%10);
}
traverseList(head);
int len =lenList(head);
printf("len=%d\n",len);
#if 0
Node* pfind=searchList(head,8);
if(pfind!=NULL)
{
printf("find in the list\n");
// deleteList(head,pfind); //只能删除一个8
do
{
deleteList(head,pfind); //利用do while 能删除所有 8
}
while(pfind=searchList(head,8));
traverseList(head);
}
#endif
popSortList(head);
traverseList(head);
reverseList(head);
traverseList(head);
destoryList(head);
return 0;
}