1. 双向链表
每个节点都有一个向后的指针和一个向前的指针
//DLlist.h
#ifndef _DOUBLELINKLIST_H_
#define _DOUBLELINKLIST_H_
#define ElementType int
typedef struct DoubleLinkList DLlist;
typedef struct Node SNode;
struct Node
{
ElementType data;
SNode* next;
SNode* prev;
};
struct DoubleLinkList
{
SNode* head;
SNode* tail;
int len;
};
int InitDLlist(DLlist* list);
void InsertTail(DLlist* list,ElementType element);
void InsertHead(DLlist* list,ElementType element);
void InsertIndex(DLlist* list,ElementType element,int index);
void RemoveIndex(DLlist* list,int index);
int FindFirstByElement(DLlist* list,ElementType element);//返回要找元素的下标
void RemoveElement(DLlist* list,ElementType element);
int* FindIndex(DLlist* list,int index);
int* FindElement(DLlist* list,ElementType element);
void SetIndex(DLlist* list,ElementType element,int index);
void SetElement(DLlist* list,ElementType oldelement,ElementType newelement);
void FreeDLlist(DLlist* list);
void Travel(DLlist* list);
#endif
//DLlist.c
#include<stdio.h>
#include<stdlib.h>
#include"DoubleLinkList.h"
#define true 1
#define false 0
int InitDLlist(DLlist* list)
{
list->head=NULL;
list->tail=NULL;
list->len=0;
return true;
}
SNode* CreateNode(ElementType element)
{
SNode* NewNode=(SNode*)malloc(sizeof(SNode));
if(NewNode==NULL)
{
printf("CreateNode malloc error\n");
return NULL;
}
NewNode->next=NULL;
NewNode->prev=NULL;
NewNode->data=element;
return NewNode;
}
void InsertTail(DLlist *list, ElementType element)
{
SNode* NewNode=CreateNode(element);
if(NewNode==NULL)
{
printf("InsertTail CreateNode error\n");
return;
}
if(list->len==0) //链表是空的情况,那么这个数既是头也是尾/***********************************************
/**********************************************/
{
list->head=NewNode;
list->tail=NewNode;
}
else
{
list->tail->next=NewNode;
NewNode->prev=list->tail;
list->tail=NewNode;
}
list->len++;
}
void InsertHead(DLlist *list, ElementType element)
{
SNode* NewNode=CreateNode(element);
if(NewNode==NULL)
{
printf("InsertTail CreateNode error\n");
return;
}
if(list->len==0) //链表是空的情况,那么这个数既是头也是尾
{
list->head=NewNode;
list->tail=NewNode;
}
else
{
list->head->prev=NewNode;
NewNode->next=list->head;
list->head=NewNode; //将他设为新的头
}
list->len++;
}
void InsertIndex(DLlist *list, ElementType element, int index)
{
if(index<0 ||index>list->len)
{
printf("Insert invalid place\n");
return;
}
SNode* NewNode=CreateNode(element);
if(NewNode==NULL)
{
printf("Insert Create error\n");
return;
}
if(index==0)/*****************************************************************************************/
{
InsertHead(list,element);
return;
}
if(index==list->len)
{
InsertTail(list,element);
return;
}
struct Node* TravelPoint = list->head;
while(index != 0)
{
TravelPoint = TravelPoint->next;
index--;
}
NewNode->prev=TravelPoint->prev;
TravelPoint->prev->next=NewNode;
NewNode->next=TravelPoint;
TravelPoint->prev=NewNode;
list->len++;
return;
}
void RemoveIndex(DLlist *list, int index)/********************************************************************/
{ //三种情况:1 删的是头或者尾,那么头无前驱,尾无后继
// 2 链表只有一个节点,无头无尾
// 3 正常的中间那个节点
if(index<0 || index >=list->len )
{
printf("Removeindex Invaild place!\n");
return;
}
if(index==0) //1 头
{
if(list->len==1) //2
{
free(list->head);
list->head=NULL;
list->tail=NULL;
list->len=0;
return;
}
SNode* freenode=list->head; //记录下头以便释放
list->head=list->head->next;
list->head->prev=NULL;
free(freenode);
list->len--;
return;
}
if(index==list->len-1) //2 尾
{
SNode* freenode=list->tail;
list->tail=list->tail->prev;
list->tail->next=NULL;
free(freenode);
list->len--;
return;
}
// 3 正常
SNode* TravelPoint=list->head;
while(index!=0)
{
TravelPoint=TravelPoint->next;
index--;
}
SNode* PrevNode = TravelPoint->prev;
SNode* NextNode = TravelPoint->next;
PrevNode->next=NextNode;
NextNode->prev=PrevNode;
free(TravelPoint);
list->len--;
}
int FindFirstByElement(DLlist *list, ElementType element)
{
int count=0; //下标
SNode* TravelPoint=list->head;
while(TravelPoint!=NULL)
{
if(TravelPoint->data==element)
{
return count;
}
count++;
TravelPoint=TravelPoint->next;
}
return -1; //如果没找到,返回一个非法下标
}
void RemoveElement(DLlist *list, ElementType element)
{
int index=FindFirstByElement(list,element);
while(index!=-1) //index!=-1说明还没找完
{
RemoveIndex(list,index);
index=FindFirstByElement(list,element);
}
}
int* FindIndex(DLlist *list, int index)
{
if(index<0 || index >=list->len )
{
printf("Setindex Invaild place!\n");
return NULL;
}
SNode* TravelPoint =list->head;
while(index!=0)
{
TravelPoint=TravelPoint->next;
index--;
}
return &TravelPoint->data;
}
int* FindElement(DLlist *list, ElementType element)
{
int* array=(int*)malloc(sizeof(int)*list->len+1);
if(array==NULL)
{
printf("FindElement Malloc Error\n");
return NULL;
}
int count=0;
int i=0;
SNode* TravelPoint =list->head;
while(TravelPoint!=NULL)
{
if(TravelPoint->data==element)
{
count++;
array[count]=i;
}
i++;
TravelPoint=TravelPoint->next;
}
array[0]=count;
return array;
}
void SetIndex(DLlist *list, ElementType element, int index)
{
if(index<0 || index >=list->len )
{
printf("Setindex Invaild place!\n");
return;
}
SNode* TravelPoint =list->head;
while(index!=0)
{
TravelPoint=TravelPoint->next;
index--;
}
TravelPoint->data=element;
}
void SetElement(DLlist *list, ElementType oldelement, ElementType newelement)
{
int index=FindFirstByElement(list,oldelement);
while(index!=-1)
{
SetIndex(list,newelement,index);
index=FindFirstByElement(list,oldelement);
}
}
void FreeDLlist(DLlist *list)
{
while(list->head!=NULL) //每次放头,头指针指向的地址是空,意味着链表是空的
{
SNode* freenode=list->head;
list->head=list->head->next;
free(freenode);
}
list->tail=NULL;/*******************************************************************************************/
list->len=0;
}
void Travel(DLlist *list)
{ //要保证从前往后的指针和从后往前的指针都没问题,所以要travel两次
printf("len: %d \n",list->len);
printf("next: ");
SNode* TravelPoint=list->head;
while(TravelPoint!=NULL)
{
printf("%d ",TravelPoint->data);
TravelPoint=TravelPoint->next;
}
printf("\n");
printf("prev: ");
TravelPoint=list->tail;
while(TravelPoint!=NULL)
{
printf("%d ",TravelPoint->data);
TravelPoint=TravelPoint->prev;
}
printf("\n");
}
2. 循环链表
首尾相连 (蓝色,看看即可)
//头文件与双向链表一致,DCLlist.c
#include<stdio.h>
#include<stdlib.h>
#include"DoubleCircleLinkList.h"
#define true 1
#define false 0
int InitDCLlist(DCLlist *list)
{
list->head=NULL;
list->tail=NULL;
list->len=0;
return true;
}
SNode* CreateNode(ElementType element)
{
SNode* NewNode=(SNode*)malloc(sizeof(SNode));
if(NewNode==NULL)
{
printf("CreateNode malloc error\n");
return NULL;
}
NewNode->next=NULL;
NewNode->prev=NULL;
NewNode->data=element;
return NewNode;
}
void InserTail(DCLlist *list, ElementType element)
{
SNode* NewNode=CreateNode(element);
if(NewNode==NULL)
{
printf("InsertTail CreateNode error\n");
return;
}
if(list->len==0)
{
list->head=NewNode;
list->tail=NewNode;
}
else
{
list->tail->next=NewNode;
NewNode->prev=list->tail;
list->tail=NewNode;
//***********下面两句和双链表不一样,作用是首尾相连
list->tail->next=list->head;
list->head->prev=list->tail;
}
list->len++;
}
void InsertHead(DCLlist *list, ElementType element)//************
{ //先尾插,然后头尾指针前移
InserTail(list,element);
if(list->len>1)
{
list->tail=list->tail->prev; //先在尾巴后插入一个数然后头指针前移,假装是头插
list->head=list->head->prev;
}
}
void RemoveIndex(DCLlist *list, int index)
{
if(index<0 || index >=list->len )
{
printf("Removeindex Invaild place!\n");
return;
}
if(index==0)
{
if(list->len==1)
{
free(list->head);
list->head=NULL;
list->tail=NULL;
list->len=0;
return;
}
SNode* freenode=list->head;
list->head=list->head->next;
list->head->prev=list->tail;//**
list->tail->next=list->head;//**
free(freenode);
list->len--;
return;
}
if(index==list->len-1)
{
SNode* freenode=list->tail;
list->tail=list->tail->prev;
list->tail->next=list->head;//**
list->head->prev=list->tail;//**
free(freenode);
list->len--;
return;
}
SNode* TravelPoint=list->head;
while(index!=0)
{
TravelPoint=TravelPoint->next;
index--;
}
SNode* PrevNode = TravelPoint->prev;
SNode* NextNode = TravelPoint->next;
PrevNode->next=NextNode;
NextNode->prev=PrevNode;
free(TravelPoint);
list->len--;
}
void RemoveElement(DCLlist *list, ElementType element)
{
int index=FindFirstByElement(list,element);
while(index!=-1)
{
RemoveIndex(list,index);
index=FindFirstByElement(list,element);
}
}
int FindFirstByElement(DCLlist *list, ElementType element)
{
int count=0;
SNode* TravelPoint=list->head;
while(TravelPoint!=list->tail)//**
{
if(TravelPoint->data==element)
{
return count;
}
count++;
TravelPoint=TravelPoint->next;
}
if(list->tail!=NULL && list->tail->data==element)//**
{
return count;
}
return -1; //如果没找到,返回一个非法下标
}
void Travel(DCLlist *list)
{
if(list->len==0)//**
return;
printf("len: %d \n",list->len);
printf("next: ");
SNode* TravelPoint=list->head;
while(TravelPoint!=list->tail)//**头就是尾的时候
{
printf("%d ",TravelPoint->data);
TravelPoint=TravelPoint->next;
}
printf("%d ",list->tail->data); //**
printf("\n");
printf("prev: ");
TravelPoint=list->tail;
while(TravelPoint!=list->head)//**
{
printf("%d ",TravelPoint->data);
TravelPoint=TravelPoint->prev;
}
printf("%d ",list->head->data); //**
printf("\n");
}
void FreeDCLlist(DCLlist *list)
{
if(list->len==0)//**
return;
while(list->head!=list->tail) //**头就是尾的时候
{
SNode* freenode=list->head;
list->head=list->head->next;
free(freenode);
}
free(list->head); //**
list->head=NULL;
list->tail=NULL;
list->len=0;
}
3. 约瑟夫环
#include<stdio.h>
#include<stdlib.h>
#include"DoubleCircleLinkList.h"
int main()
{
DCLlist list;
InitDCLlist(&list);
for(int i=0;i<13;i++)
{
InserTail(&list,i+1);
}
Travel(&list);
// 约瑟夫环
int count=1;
SNode* TravelPoint=list.head;
while(list.len!=1)
{
if(count==3)
{
printf("%d is out!\n",TravelPoint->data);
SNode* temp=TravelPoint->next;
RemoveElement(&list,TravelPoint->data);
TravelPoint=temp;
count=0;
}
else{
TravelPoint=TravelPoint->next;//***********************************************
}
count++;
}
printf("%d is alive\n",list.head->data);
return 0;
}
4. 链式栈
线性表: 顺序表: 支持随机存取,插入和删除比较麻烦
链表: 插入和删除比较方便,不利于随机存取
链式栈
//LinkStack.h
#ifndef _LINKSTACK_H_
#define _LINKSTACK_H_
#include"DoubleLinkList.h"
struct LinkStack //栈结构体
{
DLlist stack; //用这个双链表来做栈
ElementType TopElement; //栈顶元素
};
typedef struct LinkStack LStack;
int InitLStack(LStack* s);
void Push(LStack* s,ElementType element);
ElementType* Pop(LStack* s);
SNode* GetTop(LStack *s);//能访问栈顶指针的接口
int IsEmpty(LStack* s);
void StackTravel(LStack*s);
#endif
//LinkStack.c
#include<stdio.h>
#include "LinkStack.h"
#define true 1
#define false 0
int InitLStack(LStack *s)
{
return InitDLlist(&s->stack);
}
void Push(LStack *s, ElementType element)
{ //链式结构除非把堆上空间申请满了,不然不会栈满
InserTail(&s->stack,element);//先进来的在最下面,就是 尾插
}
ElementType* Pop(LStack *s)
{
if(s->stack.len==0)
{
printf("the stack is empty\n");
return NULL;
}
s->TopElement=s->stack.tail->data; //栈顶是链表尾部
RemoveIndex(&s->stack,s->stack.len-1);
return &s->TopElement;
}
SNode *GetTop(LStack *s)
{
return s->stack.tail; //尾指针充当栈顶指针
}
int IsEmpty(LStack *s)
{
if(s->stack.len==0)
{
return true;
}
else
{
return false;
}
}
void StackTravel(LStack *s)
{
Travel(&s->stack);
}
5. 栈的运用:数值运算
#include <stdio.h>
#include<stdlib.h>
#include "LinkStack.h"
#define true 1
#define false 0
int IsNum(char c)
{
if(c<='9'&& c>='0')
{
return true;
}
else
{
return false;
}
}
int IsOper(char c)
{
switch(c)
{
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case '=':
return true;
default:
return false;
}
}
int Operate(int prev,int next,char symbol) //计算
{
switch(symbol)
{
case'+': return prev+next;
case'-': return prev-next;
case'*': return prev*next;
case'/':
if(next==0) //除数不能为0
{
printf("device zero!\n");
exit(-1); //exit函数的作用是退出程序-1代表非法退出
}
return prev/next;
default:
break;
}
}
int Precede(char ch1,char ch2)//运算符优先级比较
{//行是栈顶元素,列是将要入栈元素,都是加减乘除左右括号和等号
char pre[7][7]=
{
{'>','>','<','<','<','>','>'},
{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},//5,7 是( =不可能存在,垃圾值
{'>','>','>','>','<','>','>'},//5,6 是这种情况(9)无意义
{'<','<','<','<','<','=','0'},//5,1的情况是栈顶为(,将入栈是+就是类似1-(2+3)此时右边的+比(优先级高
{'>','>','>','>','0','>','>'},
{'0','0','0','0','0','0','='}
};
int i=0,j=0;
switch(ch1)
{
case'+': i=0;break;
case'-': i=1;break;
case'*': i=2;break;
case'/': i=3;break;
case'(': i=4;break;
case')': i=5;break;
case'=': i=6;break;
default:
break;
}
switch(ch2)
{
case'+': j=0;break;
case'-': j=1;break;
case'*': j=2;break;
case'/': j=3;break;
case'(': j=4;break;
case')': j=5;break;
case'=': j=6;break;
default:
break;
}
return pre[i][j];
}
int main()
{
// LStack stack;
// InitLStack(&stack);
// for(int i=0;i<10;i++)
// {
// Push(&stack,i+1);
// }
// while(GetTop(&stack)!=NULL)//尾指针是空时,栈空
// {
// printf("%d ",*Pop(&stack));
// }
// printf("\n");
//+-*/
LStack Num;
InitLStack(&Num);
LStack Oper;
InitLStack(&Oper);
char str[100]={0}; //字符
printf("please input !\n");
scanf("%[^\n]",str); //识别的输入字符直到换行为止
int i=0; //i是str[]的元素下标
while(str[i]!='\0')
{
if(IsOper(str[i])==true)
{
if(IsEmpty(&Oper)==true)
{
Push(&Oper,str[i]);
i++;
}
else
{
char symbol = Precede(GetTop(&Oper)->data,str[i]);
switch (symbol)
{
case '<' :
Push(&Oper,str[i]);
i++;
break;
case '>' :
int next=*Pop(&Num);
int prev=*Pop(&Num);
char s=*Pop(&Oper);
Push(&Num,Operate(prev,next,s));
break;
case '=': //无意义
Pop(&Oper);
i++;
break;
default:
break;
}
}
}
else if(IsNum(str[i]))
{
int num=str[i]-'0';
Push(&Num,num);
i++;
while(IsNum(str[i]))
{
int higher=*Pop(&Num);
Push(&Num,higher*10+str[i]-'0');
i++;
}
}
else if(str[i]==' ')
{
while(str[i]==' ')
{
i++;
}
}
}
printf(" the answer is %d \n",GetTop(&Num)->data);
return 0;
}
6. 队列
先进先出
//Queue.h
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include"DoubleLinkList.h"
struct LinkQueue
{
DLlist queue;
ElementType FrontData;
};
typedef struct LinkQueue LQueue;
int InitLQueue(LQueue *lq);
void QPush(LQueue* lq,ElementType element);
ElementType* QPop(LQueue* lq);
int IsQEmpty(LQueue* lq);
SNode* GetFront(LQueue* lq);
void FreeQueue(LQueue* lq);
#endif
//Queue.c
#include<stdio.h>
#include<stdlib.h>
#include "Queue.h"
#define true 1
#define false 0
int InitLQueue(LQueue *lq)
{
return InitDLlist(&lq->queue);
}
void QPush(LQueue *lq, ElementType element)
{
InsertTail(&lq->queue,element);
}
ElementType* QPop(LQueue *lq)
{
if(lq->queue.len==0)
{
printf("queue is empty\n");
return NULL;
}
lq->FrontData=lq->queue.head->data;
RemoveIndex(&lq->queue,0);
return &lq->FrontData;
}
int IsQEmpty(LQueue *lq)
{
if(lq->queue.len==0)
{
return true;
}
else
{
return false;
}
}
SNode *GetFront(LQueue *lq)
{
return lq->queue.head;
}
void FreeQueue(LQueue *lq)
{
FreeDLlist(&lq->queue);
}