@yanglt7
2018-10-21T15:51:57.000000Z
字数 13098
阅读 835
数据结构和算法
ADT 抽象数据类型Data数据元素之间逻辑关系的定义Operation操作endADT
ADT 线性表(List)Data线性表的数据对象集合为{a1,a2...,an},每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素有且仅有一个直接前驱元素,除了最后一个元素an外,每一个元素有且仅有一个直接后继元素。数据元素之间的关系是一对一的关系。OperationInitList(*L):初始化操作,建立一个空的线性表L。ListEmpty(L):判断线性表是否为空表,若线性表为空,返回true,否则返回false。ClearList(*L):将线性表清空。GetElem(L,i,*e):将线性表L中的第i个位置元素值返回给e。Locate(L,e):在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则, 返回0表示失败。ListInsert(*L,i,e):在线性表L中第i个位置插入新元素e。ListDelete(*L,i,*e):删除线性表L中第i个位置元素,并用e返回其值。ListLength(L):返回线性表L的元素个数。endADT
例 求两个集合的并集
// La表示集合A,Lb表示集合Bvoid unionL(List *La, List Lb){int La_len,Lb_len,i;ElemType e;La_len = ListLength(*La);Lb_len = ListLength(Lb);for(i=1;i<=Lb_len;i++){GetElem(Lb,i,&e);if (!LocateElem(*La,e)){ListInsert(La,++La_len,e);}}}
指的是用一段地址连续的存储单元依次存储线性表的数据元素
线性表顺序存储的结构代码:
#define MAXSIZE 20typedef int ElemType;typedef struct{ElemType data[MAXSIZE];int length; //线性表当前长度} SqList;
#define OK 1#define ERROR 0#define TRUE 1#define FALSE 0typedef int Status;//Status 是函数的类型,其值是函数结果状态代码,如OK等//初始条件,顺序线性表L已存在,1<=i<=ListLength(L)//操作结果,用e返回L中第i个数据元素的值Status GetElem(SqList L, int i, ElemType *e){if (L.length==0 || i<1 || i>L.length){return ERROR;}*e = L.data(i-1);return OK;}
//初始条件,顺序线性表L已存在,1<=i<=ListLength(L).//操作结果:在L中第i个位置之前插入新的数据元素e,L长度+1.Status ListInsert(SqList *L, int i, ElemType e){int k;if (L->length == MAXSIZE){return ERROR;}if (i<1 || i>L->length+1){return ERROR;}if (i<=L->length){for(k=L->length-1;k>=i-1;k--) {L->data[k+1] = L->data[k];}}L->data[i-1] = e;L->Length++;return OK;}
//初始条件,顺序线性表L已存在,1<=i<=ListLength(L).//操作结果:删除L的第i个数据元素,并用e返回其值,L长度-1.Status ListDelete(SqList *L, int i, ElemType *e){int k;if (L->length == 0){return ERROR;}if (i<1 || i>L->length){return ERROR;}*e = L->data[i-1];if (i<L->length){for(k=i;k<L->length;k++){L->data[k-1] = L->data[k];}}L->length--;return OK;}
特征
优点
缺点
头指针
头结点
typedef struct Node{ElemType data;//数据域struct Node* Next;//指针域} Node;typedef struct Node* LinkList;
获得链表第i个数据的算法思路
实现代码
Status GetElem(LinkList L, int i, ELemType *e){int j;LinkList p;P = L->next;j = 1;while(p && j<i){p = p->next;++j;}if (!p || j>i){return ERROR;}*e = p->data;return OK;}
单链表第i个数据插入结点的算法思路
实现代码
Status ListInsert(LinkList *L, int i, ELemType e){int j;LinkList p;P = *L;j = 1;while(p && j<i){p = p->next;++j;}if (!p || j>i){return ERROR;}s = (LinkList)malloc(sizeof(Node));s->data = e;s->next = p->next;p->next = s;return OK;}
单链表第i个数据删除结点的算法思路
实现代码
Status ListDelete(LinkList *L, int i, ELemType *e){int j;Linklist p,q;p = *L;j = 1;while(p->next && j<i){p = p->next;++j;}if (!(p->next) || j>i){return ERROR;}q = p->next;p->next = q->next;*e = q->data;free(q);return OK;}
void CreateListHead(LinkList *L, int n){LinkList p;int i;srand(time(0));*L = (LinkList)malloc(sizeof(Node));(*L)->next = NULL;for(i=0; i<n; i++){p = (LinkList)malloc(sizeof(Node));p->data = rand()%100+1;p->next = (*L)->next;(*L)->next = p;}}
void CreateListTail(LinkList *L, int n){LinkList p, r;int i;srand(time(0));*L = (LinkList)malloc(sizeof(Node));r = *L;for(i=0; i<n; i++){p = (Node*)malloc(sizeof(Node));p->data = rand()%100+1;r->next = p;r = p;}r->next = NULL;}
Status ClearList(LinkList *L){LinkList p, q;p = (*L)->next;while(p){q = p->next;free(p);p = q;}(*L)->next = NULL;return OK;}
存储分配方式:
时间性能:
查找
插入和删除
空间性能
综上所述,得出一些经验性结论
#define MAXSIZE 1000typedef struct{ElemType data; //数据int cur; //游标(cursor)} Component, StaticLinkList [MAXSIZE];
| 游标 | 5 | 2 | 3 | 4 | 0 | 6 | 7 | ... | 1 |
|---|---|---|---|---|---|---|---|---|---|
| 数据 | A | C | D | E | ... | ||||
| 下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ... | 999 |
Status InitList(StaticLinkList space){int i;for(i=0; i<MAXSIZE-1; i++){space[i].cur = i+1;}space[MAXSIZE-1].cur = 0;return OK;}
| 游标 | 6 | 5 | 3 | 4 | 0 | 2 | 7 | ... | 1 |
|---|---|---|---|---|---|---|---|---|---|
| 数据 | A | C | D | E | B | ... | |||
| 下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ... | 999 |
int Malloc_SLL(StaticLinkList space){int i = space[0].cur;if(space[0].cur){space[0].cur = space[i].cur;//把它的下一个分量用来作为备用}return i;}
//在静态链表L中第i=2个元素之前插入新的数据元素eStatus ListInsert(StaticLinkList L, int i, ElemType e){int j, k, l;k = MAXSIZE-1;if(i<1 || i>ListLength(L)+1){return ERROR;}j = Malloc_SLL(L);if(j){L[j].data = e;for(l=1; l<=i-1; l++){k = L[k].cur;}L[j].cur = L[k].cur;L[k].cur = j;return OK;}return ERROR ;}
| 游标 | 2 | 5 | 6 | 4 | 0 | 3 | 7 | ... | 1 |
|---|---|---|---|---|---|---|---|---|---|
| 数据 | A | D | E | B | ... | ||||
| 下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ... | 999 |
//删除在L中的第i个数据元素Status ListDelete(StaticLinkList L, int i){int j, k;k = MAXSIZE-1;if(i<1 || i>ListLength(L)){return ERROR;}for(j=1; j<=i-1; j++){k = L[k].cur;}j = L[k].cur;L[k].cur = L[j].cur;Free_SLL(L,j);return OK;}//将下标为k的空闲结点回收到备用链表void Free_SLL(StaticLinkList space, int k){space[k].cur = space[0].cur;space[0].cur = k;}//返回L中数据元素个数int ListLength(StaticLinkList L){int j = 0;int i = L[MAXSIZE-1].cur;while(i){i = L[i].cur;j++}return j;}
优点
缺点
总的来说,静态链表其实是为了给没有指针的编程语言设计的一种实现单链表的方法
题目:快速找到未知长度单链表的中间结点并显示
Status GetMidNode(StaticLinkList L, ElemType *e){LinkList search, mid;mid = search = L;while(search->next != NULL){//search移动的速度是mid的2倍if(search->next->next != NULL){search = search->next->next;mid = mid->next;}else{search = search->next;}}*e = mid->data;return OK;}
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表
注:并不是说循环链表一定要有头结点
其实循环链表和单链表的主要差异就在于循环的判断空链表的条件上。原来判断head->next是否为null,现在则是head->next是否等于head
//初始化循环链表void ds_init(node **pNode){int item;node *temp;node *target;printf("输入结点的值,输入0完成初始化\n");while(1){scanf("%d", &item);fflush(stdin);if(item==0){return;}if((*pNode)==NULL){//循环链表中只有一个结点*pNode = (node*)malloc(sizeof(struct CLinkList));if(!(*pNode)){exit(0);}(*pNode)->data = item;(*pNode)->next = *pNode;}else{//找到next指向第一个结点的结点for(target = (*pNode); target->next != (*pNode); target = target->next);//生成一个新的结点temp = (node*)malloc(sizeof(struct CLinkList));if(!temp){exit(0);}temp->data = item;temp->next = *pNode;target->next = temp;}}}
//链表存储结构的定义typedef struct CLinkList{int data;struct CLinkList *next;}node;//插入结点//参数:链表的第一个结点,插入的位置void ds_insert(node **pNode, int i){node *temp;node *target;node *p;int item;int j = 1;printf("输入要插入结点的值:");scanf("%d", &item);if(i==1){//新插入的结点作为第一个结点temp = (node*)malloc(sizeof(struct CLinkList));if(!temp){exit(0);}temp->data = item;//寻找到最后一个结点for(target = (*pNode); target->next != (*pNode); target = target->next);temp->next = (*pNode);target->next = temp;*pNode = temp;}else{target = *pNode;for(; j<(i-1); ++j){target = target->next;}//target指向第三个元素的temp = (node*)malloc(sizeof(struct CLinkList));if(!temp){exit(0);}temp->data = item;p = temp->next;target->next = temp;temp->next = p;}}
//删除结点void ds_delete(node **pNode, int i){node *target;node *temp;int j = 1;if(i==1){//删除的是第一个结点//找到的是最后一个结点for(target = *pNode; target->next != *pNode; target = target->next);temp = *pNode;*pNode = (*pNode)->next;target->next = *pNode;free(temp);}else{target = *pNode;for(; j < i-1; ++j){target = target->next;target->next = temp->next;free(temp);}}}
//返回结点所在位置int ds_search(node *pNode, int elem){node *target;int i = 1;for(target = pNode; target->data != elem && target->next != pNode; ++i){target = target->next;}if(target->next == pNode)//表中不存在该元素return 0;elsereturn i;}
//n个人围圈报数,报m出列,最后剩下的是几号?#include <stdio.h>#include <stdlib.h>typedef struct node{int data;struct node *next;} node;node *create(int n){node *p = NULL, *head;head = (node*)malloc(sizeof(node));p = head;node *s;int i = 1;if(0 != n){while (i<=n){s = (node *)malloc(sizeof(node));s->data = i++;p->next = s;p = s;}s->next = head->next;}free(head);return s->next;}int main(){int n = 41;int m = 3;int i;node *p = create(n);node *temp;m %= n;while(p!=p->next){for(i=1; i<m-1; i++){p = p->next;}printf("%d->", p->next->data);temp = p->next;p->next = temp->next;free(temp);p = p->next;}printf("%d\n", p->data);return 0;}
// 假设A,B为非空循环链表的尾指针LinkList Connect(LinkList A, LinkList B){LinkList p = A->next; //保存A表的头结点位置A->next = B->next->next; //B表的开始结点链接到A表尾free(B->next); //释放B表的头结点B->next = p;return B; //返回新循环链表的尾指针}
//比较步数的方法int HasLoop1(LinkList L){LinkList cur1 = L; //定义结点 cur1int pos1 = 0; // cur2 的步数while(cur1){ //cur1 结点存在LinkList cur2 = L; //定义结点 cur2int pos2 = 0; // cur2 的步数while(cur2){ //cur2 结点不为空if(cur2 == cur1){ //当cur1和cur2到达相同结点时,走过的步数一样,说明没有环if(pos1 == pos2)break;else{printf("环的位置在第%d个结点处\n", pos2);return 1; //有环并返回1}}cur2 = cur2->next; //如果发现没有环,继续下一个结点pos2++; //cur2步数自增}cur1 = cur1->next; //cur1继续向后一个结点pos1++; //cur1步数自增}return 0;}
//利用快慢指针的方法int HasLoop2(LinkList L){int step1 = 1;int step2 = 2;LinkList p = L;LinkList q = L;while(p != NULL && q != NULL && q->next != NULL){p = p->next;if(q->next != NULL)q = q->next->next;printf("p:%d, q:%d \n", p->data, q->data);if(p==q)return 1;}return 0;}
#include <stdio.h>#include <stdlib.h>#define CardNumber 13typedef struct node{int data;struct node *next;} sqlist, *linklist;linklist CreateLinkList(){linklist head = NULL;linklist s, r;int i;r = head;for(i=1; i<=CardNumber; i++){s = (linklist)malloc(sizeof(sqlist));s->data = 0;if(head == NULL)head = s;elser->next = s;r = s;}r->next = head;return head;}//发牌顺序计算void Magician(linklist head){linklist p;int j;int countnumber = 2;p = head;p->data = 1; //第一张牌放1while(1){for(j=0; j<countnumber; j++){p = p->next;if(p->data != 0) //该位置有牌的话,则下一个位置{p->next;j--;}}if(p->data == 0){p->data = countnumber;countnumber++;if(countnumber == 14)break;}}}int main(){linklist p;int i;p = CreateLinkList();Magician(p);printf("按如下顺序排列: \n");for(i=0; i<CardNumber; i++){printf("黑桃%d ", p->data);p = p->next;}return 0;}
typedef struct DualNode{ElemType data;struct DualNode *prior;struct DualNode *next;}DualNode, *DuLinkList;
s->next = p;s->prior = p->prior;p->prior->next = s;p->prior = s;
p->prior->next = p->next;p->next->prior = p->prior;free(p);
#include <stdio.h>#include <stdlib.h>#define OK 1#define ERROR 0typedef char ElemType;typedef int Status;typedef struct DualNode{ElemType data;struct DualNode *prior;struct DualNode *next;}DualNode, *DuLinkList;Status InitList(DuLinkList *L){DualNode *p, *q;int i;*L = (DuLinkList)malloc(sizeof(DualNode));if (!(*L))return ERROR;(*L)->prior = (*L)->next = NULL;p = (*L);for(i=0; i<26; i++){q = (DualNode *)malloc(sizeof(DualNode));if (!q)return ERROR;q->data = 'A'+i;q->prior = p;q->next = p->next;p->next = q;p = q;}p->next = (*L)->next;(*L)->next->prior = p;return OK;}void Caesar(DuLinkList *L, int i){if (i>0){do{(*L) = (*L)->next;} while(--i);}if(i<0){do{(*L) = (*L)->next;} while(++i);}}int main(){DuLinkList L;int i, n;InitList(&L);printf("请输入一个整数:");scanf("%d", &n);printf("\n");Caesar(&L, n);for(i=0; i<26; i++){L = L->next;printf("%c", L->data);}printf("\n");return 0;}