1、前言
线性表是最常用且是最简单的一种数据结构。形如:A1、A2、A3….An这样含有有限的数据序列,我们就称之为线性表。
2、线性表的两种表示形式
①顺序表示(其实就是数组)
②链表表示(单项/双向,带头/不带头,循环/不循环)
可组成八种不同的链表形式
3 、 最简单基本的不带头单项不循环链表
①基本运算的实现
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define ERROR 0;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
LinkList InitList(LinkList L)
{
LinkList node = NULL;
node=(LinkList)malloc(sizeof(LNode));
if(!node)
{
return ERROR;
}
node->next=NULL;
L=node;
return L;
}
int ListLength(LinkList L)
{
LinkList p=NULL;
int count=0;
p=L;
while(p->next)
{
count++;
p=p->next;
}
return count;
}
LinkList CreateList_L(LinkList L,int n)
{
int i;
LinkList p=NULL;
for(i=n;i>0;i--)
{
p=(LinkList)malloc(sizeof(LNode));
scanf("%d",&p->data);
p->next=L->next;
L->next=p;
}
return L;
}
LinkList ListInsert(LinkList L,int i,int e)
{
int j=0;
LinkList s=NULL,p=NULL;
p=L;
while(p&&j<i-1)
{
p=p->next;
j++;
}
if(!p||j>i-1)
{
printf("输入的位置不合法!\n");
return L;
}
s=(LinkList)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return L;
}
LinkList ListDelete(LinkList L,int i)
{
int j;
LinkList q=NULL,p=NULL;
p=L;
j=0;
while(p->next&&j<i-1)
{
p=p->next;
j++;
}
if(!(p->next)||j>i-1)
{
printf("输入的位置不合法!!\n");
return L;
}
q=p->next;
p->next=q->next;
free(q);
return L;
}
int GetElem(LinkList L,int i)
{
int j,e;
LinkList p=NULL;
if(i<1||i>ListLength(L))
{
printf("输入的位置不合法!\n");
return false;
}
p=L->next;
j=1;
while(j<i)
{
p=p->next;
j++;
}
e=p->data;
printf("第%d位的数据元素为%d\n",i,e);
}
void menu(){
printf("*************目录**************\n");
printf("输出单链表中的各元素值1\n");
printf("在单链表中插入数据元素2\n");
printf("在单链表中删除数据元素3\n");
printf("取出单链表中的数据元素4\n");
printf("结束程序0\n");
printf("*******************************\n");
}
void main()
{
int n,m,i,e;
LinkList L=NULL,p=NULL;
L=InitList(L);
printf("请输入元素个数:");
scanf("%d",&n);
printf("依次输入%d个数据元素:",n);
L=CreateList_L(L,n);
do
{
printf("\n\n");
menu();
printf("请输入你的选择:");
scanf("%d",&m);
switch(m)
{
case 1:
printf("现在链表的元素为:");
p=L->next;
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;
}
printf("\n");
break;
case 2:
printf("依次输入插入位置和数据元素(空格隔开):");
scanf("%d%d",&i,&e);
L=ListInsert(L,i,e);
break;
case 3:
printf("输入需要删除的元素的位置:");
scanf("%d",&i);
L=ListDelete(L,i);
break;
case 4:
printf("输入需要取出的元素的位置:");
scanf("%d",&i);
GetElem(L,i);
break;
case 0:
printf("已结束程序!!!\n");
break;
default:
printf("输入错误!!!\n");
}
}while(m!=0);
}
4 、双向带头循环链表
①概念
双向循环链表的节点包含一个数据域,两个指针域,一个指针域指向上一个节点,另一个指针域指向下一个节点,这样双向循环链表构成了两个相反方向遍历的圆环,双向循环链表与单链表相比,提高了访问的效率,也付出了多维护一个指针的代价,双向循环链表的插入和删除操作比单向链表复杂,查找和修改和单向链表的算法一样
②代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DoubleList.h"
List_t *initialList(int size)
{
List_t *temp;
temp = malloc(sizeof(List_t));
if (temp == NULL)
{
return NULL;
}
temp->size = size;
temp->n = 0;
temp->head.next = &temp->head;
temp->head.prev = &temp->head;
return temp;
}
void insertNode(Node_t *P, Node_t *N, Node_t *newNode)
{
newNode->next = N;
newNode->prev = P;
N->prev = newNode;
P->next = newNode;
}
int appendListTop(List_t *list, void *data)
{
Node_t *newNode;
newNode = malloc(sizeof(Node_t));
if (NULL == newNode)
{
return -1;
}
newNode->datap = malloc(list->size);
if (NULL == newNode->datap)
{
free(newNode);
return -2;
}
memmove(newNode->datap, data, list->size);
insertNode(&list->head,list->head.next,newNode);
list->n += 1;
return 0;
}
int appendListTail(List_t *list, void *data)
{
Node_t *newNode;
newNode = malloc(sizeof(Node_t));
if (NULL == newNode)
{
return -1;
}
newNode->datap = malloc(list->size);
if (NULL == newNode->datap)
{
free(newNode);
return -2;
}
memmove(newNode->datap, data, list->size);
insertNode(list->head.prev,&list->head,newNode);
list->n += 1;
return 0;
}
int sortInsert(List_t *list, compare_t *func, void *data)
{
Node_t *newNode;
newNode = malloc(sizeof(Node_t));
if (NULL == newNode)
{
return -1;
}
newNode->datap = malloc(list->size);
if (NULL == newNode->datap)
{
free(newNode);
return -2;
}
memmove(newNode->datap, data, list->size);
Node_t *i;
for (i = list->head.next; i != &list->head; i = i->next)
{
if (func(i->datap,data) >= 0)
{
break;
}
}
insertNode(i->prev,i,newNode);
list->n += 1;
return 0;
}
void *searchListOneByItem(List_t *list, compare_t *func, void *item)
{
Node_t *i;
i = list->head.next;
while (i != &list->head)
{
if (func(i->datap, item) == 1)
{
return i->datap;
}
i = i->next;
}
return NULL;
}
List_t *searchListByItem(List_t *list, compare_t *func, void *item)
{
List_t *result;
Node_t *i;
result = initialList(list->size);
if (NULL == result)
{
return NULL;
}
i = list->head.next;
while (i != &list->head)
{
if (func(i->datap, item) == 1)
{
appendListTail(result, i->datap);
}
i = i->next;
}
if (0 == result->n)
{
return NULL;
}
return result;
}
int deleteListOneByItem(List_t *list, compare_t *func, void *item)
{
Node_t *i = list->head.next;
while (i != &list->head)
{
if (func(i->datap, item) == 1)
{
i->next->prev = i->prev;
i->prev->next = i->next;
free(i->datap);
free(i);
list->n -= 1;
return 0;
}
i = i->next;
}
return -1;
}
int deleteListByItem(List_t *list, compare_t *func, void *item)
{
int count = 0;
Node_t *i, *next;
i = list->head.next;
while (i != &list->head)
{
if (func(i->datap, item) == 1)
{
next = i->next;
i->next->prev = i->prev;
i->prev->next = i->next;
free(i->datap);
free(i);
list->n -= 1;
count++;
i = next;
continue;
}
i = i->next;
}
return count;
}
void sortList(List_t *list, compare_t *func)
{
Node_t *i, *j;
void *temp;
for (i = list->head.next; i != &list->head; i = i->next)
{
for (j = i->next; j != &list->head; j = j->next)
{
if (func(i->datap, j->datap) == 1)
{
temp = i->datap;
i->datap = j->datap;
j->datap = temp;
}
}
}
}
int saveListToFile(List_t *list, char *file)
{
FILE *fout;
int ret;
fout = fopen(file,"w");
if (NULL == fout)
{
return -1;
}
ret = fwrite(&list->size,sizeof(int),1,fout);
if (ret != 1)
{
fclose(fout);
return -2;
}
Node_t *i = list->head.next;
while (i != &list->head)
{
ret = fwrite(i->datap,list->size,1,fout);
if (ret != 1)
{
fclose(fout);
return -3;
}
i = i->next;
}
fclose(fout);
return 0;
}
List_t *loadListFromFile(char *file)
{
List_t *result;
FILE *fin;
int ret;
fin = fopen(file, "r");
if (NULL == fin)
{
goto exit1;
}
result = initialList(0);
if (NULL == result)
{
goto exit2;
}
ret = fread(&result->size,sizeof(int),1,fin);
if (1 != ret)
{
goto exit3;
}
void *data = malloc(result->size);
if (NULL == data)
{
goto exit3;
}
while (1)
{
ret = fread(data,result->size,1,fin);
if (ferror(fin))
{
goto exit4;
}
else if (feof(fin))
{
break;
}
ret = appendListTail(result,data);
if (ret != 0)
{
goto exit4;
}
}
fclose(fin);
free(data);
return result;
exit4:
free(data);
exit3:
destroyList(result);
exit2:
fclose(fin);
exit1:
return NULL;
}
void traverseListForward(List_t *list, void (*func)(void *data))
{
Node_t *i;
for (i = list->head.next; i != &list->head; i = i->next)
{
func(i->datap);
}
}
void traverseListBackward(List_t *list, void (*func)(void *data))
{
Node_t *i;
for (i = list->head.prev; i != &list->head; i = i->prev)
{
func(i->datap);
}
}
int isEmptyList(List_t *list)
{
return list->head.next == &list->head &&
list->head.prev == &list->head;
}
void destroyList(List_t *list)
{
Node_t *i, *next;
i = list->head.next;
while (i != &list->head)
{
next = i->next;
free(i->datap);
free(i);
i = next;
}
free(list);
}