1、线性表:具有相同类型数据元素的有限序列
线性表的长度:有限序列中所含元素的个数
头元素:线性表的第一个元素,无前驱
尾元素:线性表的最后一个元素,无后继
基本操作:增删改查
2、顺序表:线性表的顺序存储,用一段连续的地址依次存储,c语言中用一维数组
(1)顺序表的存储结构:
#define MAXLENGTH 20 struct sequencelist { int data[MAXLENGTH]; int length; };顺序表包含三点:a、存储的起始位置,数组data;b、线性表的最大长度MAXLENGTH;c、线性表的长度length。
(2)增:线性表的插入操作
//insert opration int insert(struct sequencelist *list,int index,int element) { int length = list->length; if(length ==0 || index < 0 || index > length || length >= MAXLENGTH) return ERROR; list->data[index] = element; for(int i = length - 1;i>index;i--) { list->data[i+1] = list->data[i]; } list->length++; return OK; }注:a、index为插入的位置,element为插入的元素b、增操作要进行判断:是否为空;是否已满等;index是否在合法位置。
c、增操作需要将原来的数据后移。所以要从尾元素操作
d、线性表长度+1
(3)删:线性表的删除操作
// Delete opration int delete(struct sequencelist *list,int index) { int length = list->length; if(length ==0 || index < 0 || index > length-1 ) return ERROR; for(int i = index;i<length-1;i++) { list->data[i] = list->data[i+1]; } list->data[length-1] = '\0';//delete the last element. list->length--; return OK; }注:a、异常返回错误
b、从删除的位置index开始操作,然后移位
c、表长减1
(4)查:线性表的取元素操作
按索引查找
//get list elements //make sure elemet is NOT NULL when calling. int getElement(struct sequencelist list,int index,int *element) { printf("\ngetElement\n"); int length = list.length; printf("length is %d\n",length); if(length ==0 || index < 0 || index >= length) return ERROR; *element = list.data[index]; return OK; }
从程序中可以看出增删操作的时间复杂度都是0(n),所以这两项操作都是不是它的强项。而查找操作的时间复杂度是O(1),那
么线性表的顺序存储结构的优势就是可以快速的取出任意位置的元素。
//lincoln //linear list //Sequence Storage Structure // #include <stdio.h> #define OK 1 #define ERROR -1 #define TURE 1 #define FALSE 0 #define MAXLENGTH 20 struct sequencelist { int data[MAXLENGTH]; int length; }; //get list elements //make sure elemet is NOT NULL when calling. int getElement(struct sequencelist list,int index,int *element) { printf("\ngetElement\n"); int length = list.length; printf("length is %d\n",length); if(length ==0 || index < 0 || index >= length) return ERROR; *element = list.data[index]; return OK; } //insert opration // int insert(struct sequencelist *list,int index,int element) { printf("\ninsert\n"); int length = list->length; printf("length is %d\n",length); if(length ==0 || index < 0 || index > length || length >= MAXLENGTH) return ERROR; list->data[index] = element; for(int i = length - 1;i>index;i--) { list->data[i+1] = list->data[i]; } list->length++; return OK; } // Delete opration // int delete(struct sequencelist *list,int index) { printf("\ndelete\n"); int length = list->length; printf("length is %d\n",length); if(length ==0 || index < 0 || index > length-1 ) return ERROR; for(int i = index;i<length-1;i++) { printf("delete data[%d]\n",i); list->data[i] = list->data[i+1]; } list->data[length-1] = '\0';//delete the last element. list->length--; return OK; } int main() { struct sequencelist list = { {3,1,5,7,12,78,34}, 7 }; printf("list length : %d\n",list.length); //Test get int *element = 0, test = 8; element = &test; if(OK == getElement(list,2,element)) { printf("list get 2 :%d\n", *element); } //Test insert if(OK == insert(&list,7,520)) { printf("list insert 7 ok!\n"); } if(OK == getElement(list,7,element)) { printf("list get 7 :%d\n", *element); } if(OK == insert(&list,3,520)) { printf("list insert 3 ok!\n"); } if(OK == getElement(list,3,element)) { printf("list get 3 :%d\n", *element); } //Test delete if(OK == delete(&list,3)) { printf("list delete 3 ok!\n"); } if(OK == getElement(list,3,element)) { printf("list get 3 :%d\n", *element); } if(OK == delete(&list,6)) { printf("list delete 6 ok!\n"); } if(OK == getElement(list,6,element)) { printf("list get 6 :%d\n", *element); } else { printf("list get ERROR!\n"); } }
3、链表:线性表的链式存储结构——>结点
(1)结点由数据域和指针域两个部分组成
typedef char DataType; //假设结点的数据域类型为字符 typedef struct node{ //结点类型定义 DataType data; //结点的数据域 struct node *next;//结点的指针域 }ListNode; typedef ListNode *LinkList; ListNode *p; LinkList head;
注意:
①LinkList和ListNode *是不同名字的同一个指针类型(命名的不同是为了概念上更明确)
②LinkList类型的指针变量head表示它是单链表的头指针
③ListNode *类型的指针变量p表示它是指向某一结点的指针
(2)指针变量和结点变量
指针变量p的值—— 结点地址
结点变量*p的值—— 结点内容
(*p).data的值——p指针所指结点的data域的值
(*p).next的值——*p后继结点的地址
*((*p).next)——*p后继结点
注意: 若指针变量p的值为空(NULL),则它不指向任何结点。此时,若通过*p来访问结点就意味着访问一个不存在的
变量,从而引起程序的错误。
①生成结点变量的标准函数
p=( ListNode *)malloc(sizeof(ListNode));
//函数malloc分配一个类型为ListNode的结点变量的空间,并将其首地址放入指针变量p中
②释放结点变量空间的标准函数
free(p);//释放p所指的结点变量空间
③结点分量的访问
利用结点变量的名字*p访问结点分量
方法一:(*p).data和(*p).next
方法二:p-﹥data和p-﹥next
【单链表】
1、由于线形表中的每个元素至多只有一个前驱元素和一个后续元素,即元素之间是一对一的逻辑关系,所以当用链表存储时,一种最简单也最常用的方式是:在每个结点中除包含数据域外,只设置一个指针域,用于指向其后继结点。这样构成的链
表成为单链表。
2.、单链表分为带头结点和不带头结点两种。在带头结点的单链表中,头结点不存放数据元素,其指针域指向首元素结点。
3、基本操作
//////////////////////////////////////////// //单链表的初始化,建立,插入,查找,删除。// //Author:Wang Yong // //Date: 2010.8.19 // //////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> typedef int ElemType; //////////////////////////////////////////// //定义结点类型 typedef struct Node { ElemType data; //单链表中的数据域 struct Node *next; //单链表的指针域 }Node,*LinkedList; //////////////////////////////////////////// //单链表的初始化 LinkedList LinkedListInit() { Node *L; L = (Node *)malloc(sizeof(Node)); //申请结点空间 if(L == NULL) //判断是否有足够的内存空间 printf("申请内存空间失败/n"); L->next = NULL; //将next设置为NULL,初始长度为0的单链表 } //////////////////////////////////////////// //单链表的建立1,头插法建立单链表 LinkedList LinkedListCreatH() { Node *L; L = (Node *)malloc(sizeof(Node)); //申请头结点空间 L->next = NULL; //初始化一个空链表 ElemType x; //x为链表数据域中的数据 while(scanf("%d",&x) != EOF) { Node *p; p = (Node *)malloc(sizeof(Node)); //申请新的结点 p->data = x; //结点数据域赋值 p->next = L->next; //将结点插入到表头L-->|2|-->|1|-->NULL L->next = p; } return L; } //////////////////////////////////////////// //单链表的建立2,尾插法建立单链表 LinkedList LinkedListCreatT() { Node *L; L = (Node *)malloc(sizeof(Node)); //申请头结点空间 L->next = NULL; //初始化一个空链表 Node *r; r = L; //r始终指向终端结点,开始时指向头结点 ElemType x; //x为链表数据域中的数据 while(scanf("%d",&x) != EOF) { Node *p; p = (Node *)malloc(sizeof(Node)); //申请新的结点 p->data = x; //结点数据域赋值 r->next = p; //将结点插入到表头L-->|1|-->|2|-->NULL r = p; } r->next = NULL; return L; } //////////////////////////////////////////// //单链表的插入,在链表的第i个位置插入x的元素 LinkedList LinkedListInsert(LinkedList L,int i,ElemType x) { Node *pre; //pre为前驱结点 pre = L; int tempi = 0; for (tempi = 1; tempi < i; tempi++) pre = pre->next; //查找第i个位置的前驱结点 Node *p; //插入的结点为p p = (Node *)malloc(sizeof(Node)); p->data = x; p->next = pre->next; pre->next = p; return L; } //////////////////////////////////////////// //单链表的删除,在链表中删除值为x的元素 LinkedList LinkedListDelete(LinkedList L,ElemType x) { Node *p,*pre; //pre为前驱结点,p为查找的结点。 p = L->next; while(p->data != x) //查找值为x的元素 { pre = p; p = p->next; } pre->next = p->next; //删除操作,将其前驱next指向其后继。 free(p); return L; } ///////////////////////////////////////////// int main() { LinkedList list,start; /* printf("请输入单链表的数据:"); list = LinkedListCreatH(); for(start = list->next; start != NULL; start = start->next) printf("%d ",start->data); printf("/n"); */ printf("请输入单链表的数据:"); list = LinkedListCreatT(); for(start = list->next; start != NULL; start = start->next) printf("%d ",start->data); printf("/n"); int i; ElemType x; printf("请输入插入数据的位置:"); scanf("%d",&i); printf("请输入插入数据的值:"); scanf("%d",&x); LinkedListInsert(list,i,x); for(start = list->next; start != NULL; start = start->next) printf("%d ",start->data); printf("/n"); printf("请输入要删除的元素的值:"); scanf("%d",&x); LinkedListDelete(list,x); for(start = list->next; start != NULL; start = start->next) printf("%d ",start->data); printf("/n"); return 0; }