数据结构-线性表
例1、假设有两个线性表LA和LB分别表示两个集合A和B,现要求一个新集合A=A U B(集合的并)。
算法思想:扩大线性表LA,将表LB中不在LA中出现的元素插入到LA中。只要从线性表LB中依次取出每个元素,按值在线性表LA中查找,若没查到则插入之。
算法描述:
[code]void union (Linear_List LA ,Linear_List LB) //假定Linear_List是线性表类型 { n = ListLength(LA); //求LA的表长 for(i=1;i<=ListLength(LB),i++) //遍历Linear_List LB 的元素 { x = GetNode(LB,i); //取LB中第i个元素赋值给x if(LocateNode(LA,x) == 0) //按值查找,与表LA的值一一比对 { InsertList(LA,++n,x); //在表LA的值之后插入x的值 } } }
例2、删除线性表L中重复的元素
算法思想:从表L中的第一个元素(i=1)开始,逐个检查i位置以后的任一位置j,若两元素值相同,则从表中删除第j个元素,。。。。直到i移到当前表L的最后一个位置为止。
算法描述:
[code]void purge (Linear_List L) { i =1 ; //假设从第一个元素开始,i=1 while (i<ListLength (L)) // 当 元素i 在表L内 { x = GetNode(L,i); //取表L第i个元素的值赋值给x j=i+1; //假设查找从第i+1开始 while(j<=ListLength(L)) //当 元素j 在表L内 { y=GetNode(L,j); //取表L第j个元素的值赋值给y if(x==y) //如果x等于y { DeleteList(L,j); //删除表L第j个元素 } else { j++; //否则j+1; } } i++; //当j+1后,i相应也+1 } }
例3、顺序线性表插入操作
算法描述:
[code]void InsertList(seqlist *L ,int i ,DataType x) //在顺序表L中第i个位置之前插入一个新元素x { int j ; if(i<1 || i>L->length+1) { printf("position error"); return ; } if(L->length >= ListSize) { printf("overflow"); return ; } for(j=l->length-1;j>=i-1;j--) { L->data[j+1]=L->data[j]; //从最后一个元素开始逐一后移 L->data[i-1]=x; //在第i个元素之前插入新元素x L->length++; //实际表长+1 } }
例4、顺序表删除操作
算法描述:
[code]DataType DeleteList (SeqList *L ,int i) //在顺序表L中删除第i个元素,并返回被删除元素 { int j ; DataType x; //DataType是一个通用类型标识符,在使用时再定义实际类型 if(i<1 || i->length) { printf("position error"); exit(0); //出错退出处理 } x = L->data[i]; //保存被删除元素 for(j=i;j<=L->length ;j++) { L->data[j-1]=L->data[j]; //元素前移 } L->length--; //实际表长减1 return x; //返回被删除的元素 }
例5、已知一长度为n的顺序存储的线性表,试写一算法将该线性表逆置。
算法思想:先以表长的一半作为循环控制次数,将表中最后一个元素同顺数第一个元素交换,将倒数第二个元素同顺数第二个元素交换,依此类推,直至交换完为止。
算法描述:
[code]SeqList Converts (SeqList L) { DataType x ; int i ,k ; k=L.length/2; for(i=0;i<k;i++) { x=L.data[i]; //把表L第i个元素赋值给x L.data[i]=L.data[L.length -i-1]; //把表L第L.length-i-1 个元素赋值给 第i个元素 L.data[L.length-i-1]=x; //把值x赋值给表L第L.length-i-1 个元素 } return L; //返回线性表L }
例6、试写一算法,实现在顺序表中查找出最大值和最小值的元素及所在位置。
算法思想:如果在查找最大值和最小值的元素时各扫描一遍所有元素,则至少要比较2n次,可以使用一次扫描找出最大值和最小值的元素。另外,在算法中要求带回求得的最大值和最小值元素及其所在位置,可用4个指针变量参数间接得到,也可以用外部变量实现,因为函数本身只可返回一个值。下面是采用指针变量参数来实现。
算法描述:
[code]void MaxMin (SeqList L ,DataType *max ,DataType *min ,int *k ,int *j) { int i ; *max=L.data[0]; *min=L.data[0]; *k=*j=1; //先假设第一个元素既是最大值,也是最小值。 for(i=1;i<L.length ;i++) { if(L.data[i]>*max) { *max =L.data[i]; *k=i; } else if (L.data[i]<*min) { *min =L.data[i]; *j=i; } } }
例7、用头插法建立单链表
算法思想:头插法建表是从一个空表开始,重复读入数据,生成新结点,将读入的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头上,直到读入结束标志为止。
算法描述:假设线性表中结点的数据域为字符型
[code]LinkList CreateListF() { LinkList head; ListNode *p; char ch; head =NULL; //置空单链表 ch=getchar(); //读入第一个字符 while(ch!='\n') //读入字符不是结束标志符时作循环 { p =(ListNode *)malloc(sizeof(ListNode)); //申请新结点 p->data =ch; //数据域赋值 p->next =head; //指针域赋值 head =p ; //头指针指向新结点 ch =getchar(); //读入下一个字符 } return head; //返回链表的头指针 }
例8、用尾插法建立(不带头结点)单链表
算法思想:将新结点插入在当前链表的表尾上,因此需要增设一个尾指针rear,使其始终指向链表的尾结点。
算法描述:假设线性表中结点的数据域为字符型
[code]LinkList CreateListR() { LinkList head ,rear ; ListNode *p; char ch; head =NULL; rear=NULL; //置空单链表 ch = getchar(); //读入第一个字符 while(ch!='\n') //读入字符不是结束标识符时作循环 { p=(ListNode *)malloc(sizeof(ListNode)); //申请新结点 p->data =ch; //数据域赋值 if(head==NULL) { head =p ; //新结点*p插入空表 } else { rear->next =p ; //新结点*p插入到非空表的表为结点*rear之后 } rear =p; //表尾指针指向新的表尾结点 ch =getchar(); //读入下一个字符 } if(rear!=NULL) { rear->next =NULL; //终端结点指针域置空 } return head; }
例9、用尾插法建立(带头结点)的单链表
算法思想:为简化算法,方便操作,可在链表的开始结点之前附加一个结点,并称其为头结点,
算法描述:
[code]LinkList CreateListR1() //尾插法建立带头结点的单链表算法 { LinkList head =(ListNode *)malloc(sizeof(ListNode)); //申请头结点 ListNode *p,*r ; DataType ch; r=head; //尾指针初始指向头结点 while(ch=getchar())!='\n') { p=(ListNode *)malloc(sizeof(ListNode)); //申请新结点 p->data =ch; r->next =p ; //新结点连接到尾结点之后 r= p ; //尾指针指向新结点 } r->next =NULL; //终端结点指针域置空 return head; }
例10、查找运算(带头结点),按结点序号查找
算法思想:在单链表中要查找第i个结点,就必须从链表的第1个结点(开始结点,序号为1)开始,序号为0是头结点,p指向当前结点,j为计数器,其初始值为1,当p扫描下一个结点时,计算器加1。当j=i时,指针p所指向的结点就是要找的结点。
算法描述:
[code]ListNode * GetNodei (LinkList head ,int i) //head是带头结点的单链表的头指针,i为要查找的结点序号 //若查找成功,则返回查找结点的存储地址(位置),否则返回NULL ListNode *p ; int j ; p=head ->next ; j=1; //使p指向第一个结点,j置1 while(p!=NULL && j<i) //顺指针向后查找,直到p指向第i个结点或p为空为止 { p=p->next ; ++j; } if(j==i) { return p ; } else { return NULL; }
例11、查找运算(带头结点),按结点值查找
算法思想:在单链表中按值查找结点,就是从链表的开始结点出发,顺链逐个将结点的值和给定值k进行比较,若遇到相等的值,则返回该结点的存储位置,否则返回NULL。按值查找算法要比按序号查找更为简单。
算法描述:
[code]ListNode *LocateNodek (LinkList head ,DataType k) { //head为带头结点的单链表的头指针,k为要查找的结点值 //若查找成功,则返回查找结点的存储地址(位置),否则返回NULL ListNode *p =head->next ; //p指向开始结点 while(p&&p->data! =k) //循环直到p等于NULL或p->data等于k为止 { p=p->next; //指针指向下一个结点 } return p; //若找到值为k的结点,则p指向该结点,否则p为NULL }
例12、插入运算
算法思想:先使p指向ai-1的位置,然后生成一个数据域值为x的新结点*s,再进行插入操作。
算法描述:
[code]void InsertList(LinkList head ,int i ,DataType x) { //在以head为头指针的带头结点的单链表中第i个结点的位置上 //插入一个数据域为x的新结点 ListNode *p ,*s ,int j ; p=head; j=0; while (p!=NULL && j<i-1) //使p指向第i-1个结点 { p=p->next; ++j; } if(p==NULL) //插入位置错误 { printf("ERROR\n "); return ; } else { s=(ListNode *)malloc(sizeof(ListNode)); //申请新结点 s->data =x; s->next =p->next; p->next =s; } }
例13、删除运算
算法思想:删除运算就是将链表的第i个结点从表中删去。由于第i个结点的存储地址是存储在第i-1个结点的指针域next中,因此要先使p指向第i-1个结点,然后使得p->next指向第i+1个结点,再将第i个结点释放掉。
算法描述:
[code]DataType DeleteList(LinkList head, int i) //在以head为头指针的带头结点的单链表中删除第i个结点 { ListNode *p,*s ; DataType x; int j ; p=head; j=0; while(p! =NULL&&j<i-1) //使p指向第i-1个结点 { p=p->next; ++j; } if(p==NULL) //删除位置错误 { printf(“位置错误\n”); exit(0); //出错退出处理 } else { s=p->next; //s指向第i个结点 p->next =s->next; //使p->next指向第i+1个结点 x=s->data; //保存被删除结点的值 free(s); return x; //删除第i个结点,返回结点值 } }
例14、试写一算法,将一个头结点指针为a的带头结点的单链表A分解成两个单链表A和B,其中头结点指针分别为a和b,使得A链表中含有原链表A中的序号为奇数的元素,而B链表中含有原链表为偶数的元素,并保持原来的相对顺序。
算法思想:根据题目要求,需要遍历整个链表A,当遇到序号为奇数的结点时将其链接到A表上,序号为偶数结点时,将其链接到B表中,一直到遍历结束。
算法描述:
[code]void split (LinkList a ,LinkList b) //按序号奇偶分解单链表,注意b在调用该算法前是一个带头结点的空链表 { ListNode *p ,*r ,*s ; p=a->next; //p指向表头结点 r=a; //r指向A表的当前结点 s=b; //s指向B表的当前结点 while(p!=NULL) { r->next =p ; //序号为奇数的结点链接到A表上 r=p; //r总是指向A链表的最后一个结点 p=p->next; if(p) { s->next =p ; //序号为偶数的结点链接到B表中 s=p; //s总是指向B链表的最后一个结点 p=p->next; //p指向原链表A中的偶数序号的结点 } } r->next =s->next =NULL; }
例15、假设头指针为La和Lb的单链表(带头结点)分别为线性表A和B的存储结构,两个链表都是按结点数据值递增有序的。试写一算法,将这两个单链表合并为一个有序链表Lc。
算法思想:根据题目要求需设立三个指针pa、pb、pc,其中pa和pb分别指向La表和Lb表中当前待比较插入的结点,而pc则指向Lc表当前的最后一个结点,若pa->data<=pb->data,则将pa所指向的结点之后,否则将pb所指向的结点链接到pc所指的结点之后。
算法描述:
[code]LinkList MergeList(LinkList La ,LinkList Lb) //归并两个有序链表La和Lb为有序链表Lc { ListNode * pa , *pb ,*pc ; ListList Lc; pa =La ->next ; pb =Lb ->next ; //pa和pb分别指向两个链表的开始结点 Lc =pc =La ; //用La的头结点作为Lc的头结点 while (pa!=NULL&&pb! =NULL) { if(pa->data<=pb->data) { pc->next =pa ; pc=pa; pa=pa->next; } else { pc->next=pb; pc=pb; pb=pb->next; } } pc->next =pa!=NULL?pa:pb; //插入链表剩余部分 free (Lb); //释放Lb的头结点 return Lc; //返回合并后的表 }
例16、已知有一个结点数据域为整型的,且按从大到小顺序排列的头结点指针为L的非空单循环链表,试写一算法插入一个结点(其数据域为x)至循环链表的适当位置,使之保持链表的有序性。
算法思想:要解决这个算法问题,首先就是要解决查找插入位置问题,查找就要使用循环语句,从表头开始逐个结点比较。判断整个循环链表是否比较结束,就是判断当前结点的指针域是否等于头指针。另外,由于链表是递减有序的,在查找插入位置时,循环条件是当前结点值是否要大于要插入的结点值,所以,若用q指向表中当前结点,那么循环条件应该是q->data>x&&q!=L ,还要使用一个指针p指向插入位置的前驱结点。
算法描述:
[code]void InsertList(LinkList L ,int x ) //将值为x的新结点插入到有序循环链表中适当的位置 { ListNode *s ,*p ,*q ; s =(ListNode *)malloc (sizeof(ListNode)); //申请结点存储空间 s->data =x ; p=L; q=p->next; //q指向开始结点 while(q->data>x&&q!=L) //查找插入位置 { p=p->next; //P指向q的前驱结点 q=p->next; //q指向当前结点 } p->next =s; //插入*s结点 s->next =q; }
例17、假设有一个头结点指针为head的循环双向链表,其结点类型结构包含三个域:prior、data和next。其中data为数据域,next为指针域,指向其后继结点,prior也为指针域,其值为空(NULL),因此该双向链表其实也是一个单循环链表。试写一算法,把其表修改成真正的双向循环链表。
算法思想:根据题目要求,就是要将表中的每个prior域填上相应的前驱结点地址。只要弄清楚双向循环链表的结构,其算法就非常简单。其实只需要以p指向头结点开始,循环使用语句p->next->prior=p ;和 p=p->next;即可实现题目要求。
算法描述:
[code]void trans(DLinkList head) { DLNode *p ; p =head ; //使p指向头结点 while(p->next! =head) //依次从左向右,对每个结点的prior赋值 { p->next->prior =p ; //p所指结点的直接后继结点的前驱就是p p=p->next; //p指针指向下一个结点 } head—>prior =p ; //head 的前驱指向表的终端结点 }
例18、设有两个顺序表A和B,且都递增有序。试写一算法,从A中删除与B中相同的那些元素(也就是计算A-B)。
算法思想:扫描整个B表,顺序取表中每一个元素,然后与表A中从某下标开始的元素进行比较(因为两表都是有序的,不必每次从头开始,用一个变量k标识上一次比较结束的位置),当B中某个元素值大于或等于A中某个元素时,比较结束。记住A表的当前下标值K,之后再比较两元素值是否相等,若相等,则从表A中删除该元素,而后继续B中的下一个元素与A中第k个元素开始向后比较;否则,继续,直到B中所有元素比较完为止。
算法描述:
[code]void SubList(SeqList *A ,SeqList B) { int i,j,k; k=1; //记住A表的下标位置 for(i=1;i<=B.length ;i++) { for(j=k,j<=A->length ;j++) { if (B.data[i]>=A->data[j]) //因为表是有序的,不必比较到最后 { k=j; break; //用k记住A表的当前位置,以便下一次比较从k开始 } else { continue; } if(B.data[i]==A->data[k]) //相等表示有重复的 { DeleteList(A,k); //调用删除函数,删除A中第k个元素 } } } }
例19、已知head是指向一个带头结点的单链表的头指针,p指向该链表的任一结点。试写一算法,将p所指向的结点与其后继结点位置交换。
算法思想:如果p存在后续结点,看它是否为头结点,如果是,则交换后还要改变该链表的head;若不是头结点,则直接交换,如果p指向最后一个结点,说明其没有后续结点,则不交换。
算法描述:
[code]void ExchangeNode(LinkList head ,ListNode *p) //交换p所指结点与其后续结点存储位置 { ListNode *q ,*r ,*s ; q = p->next; //q指向p的后续结点 if(q!=NULL) //表示p不是指向最后一个结点 { if(p==head) //若p指向头结点,则将该链表的前两个结点交换位置 { head=head->next; s=head->next; head-next =p ; p->next =s; } else //若p指向第二个结点之后的结点 { r=head ; //查找p的前驱结点 while(r->next! =p) { r=r->next; } r->next =q; //交换p和q的位置 p->next =q->next; q->next=p; } } else { printf("p不存在后续结点,无须进行交换"); } }
例20、已知两单链表A和B分别表示两个集合,其元素值递增有序。试写一算法,求A和B的交集C,要求C同样以元素值递增的单链表形式存储。
算法思想:两集合的交集是指两个单链表的元素值相同的结点的集合,为了操作方便,先让单链表C带头结点。
算法描述:
[code]void Bemixed(LinkList a , LinkLink b ,LinkList c) //求A和B的交集C,分别用单链表表示集合 { ListNode *p,*q,*r,*s ; c=(ListNode *)malloc(sizeof(ListNode)); //生成c表头结点 r=c; p=a; q=b; while(p!=NULL&&q!=NULL) { if(p->data<q->data) //因为表是有序的,A表元素值小,则后移一个位置 { p= p->next; } else if(p->data>q->data) //同上理由,B表元素值小 { q=q->next; } else //找到一个值相同的结点,在c中生成一个新结点 { s=(ListNode *)malloc(sizeof(ListNode)); s->data =p->data; s->next =NULL; r->next =s; //把s结点链接到C表的尾部 r=s; //r始终指向C表的最后一个结点 p=p->next; //使p、q指向其后续结点 q=q->next; } } }
例21、设有一个带头结点的双向循环链表,head为链表的头指针。试写一算法,实现在值为x的结点之前插入一个值为y的结点。
算法思想:因为链表是双向循环链表,所以不需要用指针指向x之前的结点,但要先从开始结点用循环找到要插入的位置,也就是x结点的位置。
算法描述:
[code]void DinsertB(DlinkList head ,DataType x ,DataType y) //在带头结点的双循环链表的值为x的结点之前插入一个结点 { DlistNode *p ,*s ; s=(DlistNode *)malloc(sizeof(DlistNode)); s->data =y; p=head->next; while(P!=head&&p->data!=x) { p=p->next; if(p==head) { printf("没有值为x的结点"); } else { s->prior =p->prior; s->next=p; p->prioe=s; p->prior->next=s; } } }
- 数据结构之线性表-剖析自己小问题
- [SDUT](3379)数据结构实验之查找七:线性之哈希表 ---哈希查找(查找)
- 数据结构——线性表的链式结构(C语言)
- 线性表数据结构解读(三)栈结构Stack
- 软件设计师教程 数据结构之线性链表的实现 (C/C++语言)
- 数据结构之线性表顺序结构
- 数据结构笔记二:线性表
- 数据结构实验之查找七:线性之哈希表
- 数据结构3:线性表的概念
- 【数据结构—1】线性表的概念与定义
- 数据结构之线性表--顺序存储
- 数据结构之线性表(顺序表示)
- 数据结构——线性表的顺序存储
- 线性表-约瑟夫问题(数据结构基础 第2周)
- 线性表-顺序表、链表类模板的实现(数据结构基础 第2周)
- 数据结构之线性表的线性分配动态存储
- JAVA数据结构之线性表的链式存储结构——双向链表
- 【Data】数据结构之线性表(2)
- 数据结构之线性表——双向链表
- 数据结构之线性表——链表的顺序存储(数组描述)