总结以下最近一些遇到的一些问题,一般在开发中数据结构用的页比较多,一开始都不知道如何使用,什么时候用它,什么时候不用它,先讲解一下数据结构的定义吧:
定义:数据结构其实就是另外一种存储数据的方式,和数组是有区别的,数组是顺序存储,链表是随机存储,有线性链表,链式存储。
方式: 单链表,双链表,双向循环链表,二叉树,队列,栈,树,
第一个是链表:是非顺序,非连续的存储数据
简单的链表插入和删除
第一个弄明白这个过程
一步:链表包含的两个变量,一个是指向前一个节点的指针域和一个是指向后一个节点的指针域
创建一个头结点函数
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name)
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
append====
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head
*head)
{
__list_add(new, head->prev, head);
}
有插入会想到要在哪里删除你想要的数据
#define list_entry(ptr, type, member)
container_of(ptr, type, member)
#define list_for_each_entry(pos, head, member)
for (pos = list_entry((head)->next, typeof(*pos), member);
&pos->member != (head);
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each(pos, head)
for (pos = (head)->next; pos != (head); pos = pos->next)
#define container_of(ptr, type, member) ({
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
=
#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE )0)->MEMBER)
#endif
#endif / KERNEL */
这是一个简单的链表变成
2 单链表的数据
插入:只能往前或者往后插入数据,不能同时在两边插入数据。
创建一个结点(两个变量,一个数据域和一个指针域)指针域指向后继的结点
插入-》遍历-》查找-》删除
//带头节点的单链表操作
#include
#include
struct node{
int data; //数据域
struct node *next;//指向后继节点的指针
};
//头部追加
int appendHead(struct node *h,int num);
//尾部追加
int appendTail(struct node *h,int num);
//*e===>end 记录末尾节点 初始值从头节点开始
int appendTail_t(struct node **e,int num);
/*
//删除一个节点 如果有多个数据匹配 则删除第一个
void deleteOneNode(struct node *h,int key);
//删除数据匹配的节点
void deleteNode(struct node *h,int key);
int main(void)
{
//头节点 空链
struct node head={.next=NULL};
struct node *end=&head;//记录最末尾的节点
int num;
printf("input int number(-1 over)\n");
while(1)
{
scanf("%d",&num);
if(num==-1) break;
//num插入到链表前面 成为当前第一个数据节点
//appendHead(&head,num);
//num插入到链表末尾 成为当前最后一个数据节点
//appendTail(&head,num);
//appendTail_t(&end,num);
//有序插入
sortInsert(&head,num);
}
travelList(&head);
struct node *tmp;
tmp=searchNode(&head,5);
if(tmp==NULL){
printf("Not Found.\n");
}else{
printf(">>>>>>%d\n",tmp->data);
}
//删除一个节点 如果有多个数据匹配 则删除第一个
//deleteOneNode(&head,5);
//删除数据匹配的节点
deleteNode(&head,5);
travelList(&head);
return 0;
}
int appendHead(struct node *h,int num)
{
struct node *newNode;
//分配数据节点
newNode=malloc(sizeof(struct node));
if(NULL==newNode) return -1;
//数据域赋值
newNode->data=num;
//修改新节点的指针指向原来头节点中指针所指向的位置
newNode->next=h->next;
//修改头节点中指针 指向 新节点
h->next=newNode;
return 0;
}
int appendTail(struct node *h,int num)
{
struct node *newNode;
newNode=malloc(sizeof(struct node));
if(newNode==NULL) return -1;
//数据域赋值
newNode->data=num;
//新节点指针 指向 NULL
newNode->next=NULL;
#if 1
struct node **t;
t=&h->next;//指向头指针
while(*t!=NULL)
{
t=&(*t)->next;//指向下一个节点的next指针
}
*t=newNode;
#elif 0
/*
头节点也是同类型的节点 包括头节点节所有数据节点在内
找出某节点指针next指向NULL的节点 修改其next指针 指向新节点
*/
struct node *end;
end=h;
while(end->next!=NULL)
{
end=end->next;
}
end->next=newNode;
#else
if(h->next==NULL)//空链表
{
h->next=newNode;
}
else//非空链表 找到尾节点 修改尾节点 的指针 指向 新节点
{
struct node *end;
end=h->next;
while(end->next!=NULL)
{
end=end->next;
}
end->next=newNode;
}
#endif //
return 0;
}
//*e===>end 记录末尾节点 初始值从头节点开始
//用于连续插入提高效率 只有开始需要超找末尾节点 之后直接记录
int appendTail_t(struct node **e,int num)
{
struct node *newNode;
newNode=malloc(sizeof(struct node));
if(newNode==NULL) return -1;
//数据域赋值
newNode->data=num;
//新节点指针 指向 NULL
newNode->next=NULL;
while((*e)->next!=NULL)
{
*e=(*e)->next;
}
(*e)->next=newNode;
*e=newNode;//更新指向新的末尾节点
return 0;
}
/*
有序插入:
从小到大:应插入在第一次比新节点的值大的节点之前 或者最末尾
从大到小:应插入在第一次比新节点的值小的节点之前 或者最末尾
应用快慢指针
*/
int sortInsert(struct node *h,int num)
{
struct node *newNode,*t,*s;//s:慢指针 t:快指针
newNode=malloc(sizeof(struct node));
if(newNode==NULL) return -1;
newNode->data=num;
s=h;
t=h->next;
while(t!=NULL)
{
if(t->data >= newNode->data)
{
break;
}
//
s=t;
t=t->next;
}
//插入在s t之间
newNode->next=t;
s->next=newNode;
return 0;
}
//遍历
void travelList(const struct node *h)
{
struct node *t;
t=h->next;
while(t!=NULL)
{
printf("%d ",t->data);
t=t->next;
}
putchar('\n');
}
struct node *searchNode(const struct node *h,int key)
{
struct node *t;
t=h->next;
while(t!=NULL)
{
if(t->data==key)
return t;
t=t->next;
}
return NULL;
}
/*
删除一个节点 如果有多个数据匹配 则删除第一个
由于删除一个节点需要修改其 前继节点的指针 而访问不可逆 所有快慢指针组合
t快指针用于遍历访问数据 s慢指针总是指向 t的 前继节点
*/
void deleteOneNode(struct node *h,int key)
{
struct node *t,*s;
s=h;
t=h->next;
while(t!=NULL)
{
if(t->data==key)//条件匹配 删除
{
s->next=t->next;
free(t);
break;
}
s=t;
t=t->next;
}
}
//删除数据匹配的节点
void deleteNode(struct node *h,int key)
{
#if 1
struct node **t,*cur;
t=&h->next;
while(*t!=NULL)
{
cur=*t;
if(cur->data==key)//删除
{
t=cur->next;//断链 pos->next = p->next; 如果不取地址 不解引用 就是单纯的给t赋值
free(cur);
continue;
}
t=&cur->next;//t=&(*t)->next;
}
#else
struct node *t,*s;
s=h;
t=h->next;
while(t!=NULL)
{
if(t->data==key)//条件匹配 删除
{
s->next=t->next;
free(t);
t=s;
}
s=t;
t=t->next;
}
#endif
}
因为时间有限暂时写到这里后续还会补充后面的链表的知识