這個作業屬於哪個課程 | 數據結構 |
---|---|
這個作業要求在哪里 | https://edu.cnblogs.com/campus/qdu/DS2020/homework/11232 |
這個作業的目標 | 掌握線性表的概念、順序表與鏈表的一系列算法,並對其相應算法進行分析,理解順序表、鏈表數據結構的特點 |
學號 | 2018204150 |
實驗一 順序表與鏈表
一、實驗目的
1、掌握線性表中元素的前驅、后續的概念。
2、掌握順序表與鏈表的建立、插入元素、刪除表中某元素的算法。
3、對線性表相應算法的時間復雜度進行分析。
4、理解順序表、鏈表數據結構的特點(優缺點)。
二、實驗預習
說明以下概念
1、線性表:線性表是n個具有相同特性的數據元素的有限序列。數據元素是一個抽象的符號,其具體含義在不同的情況下一般不同。在稍復雜的線性表中,一個數據元素可由多個數據項組成,此種情況下常把數據元素稱為記錄,含有大量記錄的線性表又稱文件。線性表中的個數n定義為線性表的長度,n=0時稱為空表。
2、順序表:順序表是在計算機內存中以數組的形式保存的線性表,線性表的順序存儲是指用一組地址連續的存儲單元依次存儲線性表中的各個元素、使得線性表中在邏輯結構上相鄰的數據元素存儲在相鄰的物理存儲單元中,即通過數據元素物理存儲的相鄰關系來反映數據元素之間邏輯上的相鄰關系,采用順序存儲結構的線性表通常稱為順序表。
3、鏈表:鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點(鏈表中每一個元素稱為結點)組成,結點可以在運行時動態生成。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。
三、實驗內容和要求
1、閱讀下面程序,在橫線處填寫函數的基本功能。並運行程序,寫出結果。
#include<stdio.h>
#include<malloc.h>
#define ERROR 0
#define OK 1
#define INIT_SIZE 5 /*初始分配的順序表長度*/
#define INCREM 5 /*溢出時,順序表長度的增量*/
typedef int ElemType; /*定義表元素的類型*/
typedef struct Sqlist{
ElemType *slist; /*存儲空間的基地址*/
int length; /*順序表的當前長度*/
int listsize; /*當前分配的存儲空間*/
}Sqlist;
int InitList_sq(Sqlist *L); /*聲明一個長度為5的順序表*/
int CreateList_sq(Sqlist *L,int n); /*創建一個長度為n的順序表*/
int ListInsert_sq(Sqlist *L,int i,ElemType e);/*在順序線性表L中第i個元素之前插入新元素e*/
int PrintList_sq(Sqlist *L); /*輸出順序表的元素*/
int ListDelete_sq(Sqlist *L,int i); /*刪除第i個元素*/
int ListLocate(Sqlist *L,ElemType e); /*查找值為e的元素*/
int InitList_sq(Sqlist *L){
L->slist=(ElemType*)malloc(INIT_SIZE*sizeof(ElemType));
if(!L->slist) return ERROR;
L->length=0;
L->listsize=INIT_SIZE;
return OK;
}/*InitList*/
int CreateList_sq(Sqlist *L,int n){
ElemType e;
int i;
for(i=0;i<n;i++){
printf("input data %d:",i+1);
scanf("%d",&e);
if(!ListInsert_sq(L,i+1,e))
return ERROR;
}
return OK;
}/*CreateList*/
/*輸出順序表中的元素*/
int PrintList_sq(Sqlist *L){
int i;
for(i=1;i<=L->length;i++)
printf("%5d",L->slist[i-1]);
return OK;
}/*PrintList*/
int ListInsert_sq(Sqlist *L,int i,ElemType e){
int k;
if(i<1||i>L->length+1)
return ERROR;
if(L->length>=L->listsize){
L->slist=(ElemType*)realloc(L->slist,
(INIT_SIZE+INCREM)*sizeof(ElemType));
if(!L->slist)
return ERROR;
L->listsize+=INCREM;
}
for(k=L->length-1;k>=i-1;k--){
L->slist[k+1]= L->slist[k];
}
L->slist[i-1]=e;
L->length++;
return OK;
}/*ListInsert*/
/*在順序表中刪除第i個元素*/
int ListDelete_sq(Sqlist *L,int i){
}
/*在順序表中查找指定值元素,返回其序號*/
int ListLocate(Sqlist *L,ElemType e){
}
int main(){
Sqlist sl;
int n,m,k;
printf("please input n:"); /*輸入順序表的元素個數*/
scanf("%d",&n);
if(n>0){
printf("\n1-Create Sqlist:\n");
InitList_sq(&sl);
CreateList_sq(&sl,n);
printf("\n2-Print Sqlist:\n");
PrintList_sq(&sl);
printf("\nplease input insert location and data:(location,data)\n");
scanf("%d,%d",&m,&k);
ListInsert_sq(&sl,m,k);
printf("\n3-Print Sqlist:\n");
PrintList_sq(&sl);
printf("\n");
}
else
printf("ERROR");
return 0;
}
輸入:5
1,2,3,4,5
3
運行結果:
算法分析:
算法分析:
(1)輸入線性表的元素個數,然后構建一個新的線性表;
(2)連續用CreatList函數往性表里插入元素,將其元素輸出;
(3)在下一步中輸入插入元素的位置和個數,最后一步,輸出運行后的線性表。
順序表存儲需要預留空間,算法空間復雜度O(n)
算法時間復雜度O(1)
2、為第1題補充刪除和查找功能函數,並在主函數中補充代碼驗證算法的正確性。
刪除算法代碼:
int ListDelete_sq(Sqlist *L,int i) {
int k = 0;
if(i<1||i>(L->length)) return ERROR;
for(k = i-1;k<L->length-1;k++){
L->slist[k] = L->slist[k+1];
}
L->slist[L->length-1]=NULL;
L->length--;
return OK;
}
printf("請輸入要刪除元素的位置:");/*主函數中需要增加的部分代碼*/
scanf("%d",&m);
ListDelete_sq(&sl,m);
PrintList_sq(&sl);
輸入:5
1,2,3,4,5
3
4
運行結果:
算法分析:
(1)輸入線性表的元素個數,然后構建一個新的線性表;
(2)連續用ListDelete_sq函數刪除元素,將其元素輸出;
(3)在下一步中輸入刪除元素的位置,輸出運行后的線性表。
算法時間復雜度:O(n)
查找算法代碼:
int ListLocate(Sqlist *L,ElemType e) {
int k = 0;
for(k = 0;k<L->length;k++){
if(e==L->slist[k]) return k+1;
}
return ERROR;
}
printf("\n請輸入要查找的元素:");/*主函數中需要增加的部分代碼*/
scanf("%d",&m);
int a = ListLocate(&sl,m);
if(a==0){
printf("\n元素不存在");
}else{
printf("\n%d所在的位置是%d",m,a);
}
輸入:5
1,2,3,4,5
3
4
4
運行結果:
算法分析:
(1)輸入線性表的元素個數,輸入線性表元素,然后構建一個新的線性表並輸出;
(2)用ListLocate函數查找元素,將其元素的位置輸出;
(3)在下一步中輸入元素,輸出此元素位置
算法時間復雜度:O(n)
3、閱讀下面程序,在橫線處填寫函數的基本功能。並運行程序,寫出結果。
#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
#define ERROR 0
#define OK 1
typedef int ElemType; /*定義表元素的類型*/
typedef struct LNode { /*線性表的單鏈表存儲*/
ElemType data;
struct LNode *next;
} LNode,*LinkList;
LinkList CreateList(int n); /*創建一個長度為n的鏈表*/
void PrintList(LinkList L); /*輸出帶頭結點單鏈表的所有元素*/
int GetElem(LinkList L,int i,ElemType *e); /*獲得第i個位置的元素*/
LinkList CreateList(int n) {
LNode *p,*q,*head;
int i;
head=(LinkList)malloc(sizeof(LNode));
head->next = NULL;
p=head;
for(i=0; i<n; i++) {
q=(LinkList)malloc(sizeof(LNode));
printf("input data %i:",i+1);
scanf("%d",&q->data); /*輸入元素值*/
q->next=NULL; /*結點指針域置空*/
p->next=q; /*新結點連在表末尾*/
p=q;
}
return head;
}/*CreateList*/
void PrintList(LinkList L) {
LNode *p;
p=L->next; /*p指向單鏈表的第1個元素*/
while(p!=NULL) {
printf("%5d",p->data);
p=p->next;
}
}/*PrintList*/
int GetElem(LinkList L,int i,ElemType *e) {
LNode *p;
int j=1;
p=L->next;
while(p&&j<i) {
p=p->next;
j++;
}
if(!p||j>i)
return ERROR;
*e=p->data;
return OK;
}/*GetElem*/
int main() {
int n,i;
ElemType e;
LinkList L=NULL; /*定義指向單鏈表的指針*/
printf("please input n:"); /*輸入單鏈表的元素個數*/
scanf("%d",&n);
if(n>0) {
printf("\n1-Create LinkList:\n");
L=CreateList(n);
printf("\n2-Print LinkList:\n");
PrintList(L);
printf("\n3-GetElem from LinkList:\n");
printf("input i = ");
scanf("%d",&i);
if(GetElem(L,i,&e))
printf("No%i is %d\n",i,e);
else
printf("not exists");
} else
printf("ERROR");
return 0;
}
輸入:5
2,3,4,5,6
3
運行結果:
算法分析:
(1)創建帶頭結點的單鏈表,首先輸入結點數,然后依次輸入各個結點的值;
(2)輸出單鏈表中的值;
(3)輸入查找元素的位置,輸出對應元素的值。
算法時間復雜度:O(n)
4、為第3題補充插入功能函數和刪除功能函數。並在主函數中補充代碼驗證算法的正確性。
插入算法代碼:
int LengthList(LinkList L);/*求鏈表的長度*/
int InsertList(LinkList L,int i,ElemType* e);/*在第i個位置插入元素*/
int LengthList(LinkList L){
int i = 0;
LNode* p = NULL;
for(p = L;p->next!=NULL;p=p->next){
i++;
}
return i;
}
int InsertList(LinkList L,int i) {//插在第i個位置的后面,如果要插在表頭,則i=0
if(i<0||i>LengthList(L)) return ERROR;
LNode* p;
LNode* q;
LNode* r;
int e = 0;
r = (LinkList)malloc(sizeof(LNode));
printf("輸入要插入的元素:");
scanf("%d",&e);
r->data = e;
if(i==0){
p = L;
q = p->next;
p->next = r;
r->next = q;
return OK;
}
int j = 0;
for(p = L;j < i;j++){
p=p->next;
}
q = p->next;
p->next = r;
r->next = q;
return OK;
}
printf("鏈表的長度是:%d\n",LengthList(L));/*主函數中需要增加的部分代碼*/
printf("插入的位置以及值為(插在第i個位置的后面,如果要插在表頭,則i=0):");
int a = 0,b = 0;
scanf("%d,%d",&a,&b);
InsertList(L,a);
PrintList(L);
輸入:5
2,3,4,5,6
2
4
8
運行結果:
算法分析:
(1)創建帶頭結點的單鏈表,首先輸入結點數,然后依次輸入各個結點的值;
(2)輸出單鏈表中的值;
(3)輸入插入元素的位置和插入的元素,輸出單鏈表中的值。
算法時間復雜度:O(1)
刪除算法代碼:
int DeleteList(LinkList L,int i) {
if(i<1||i>LengthList(L)) return ERROR;
LNode* p;
LNode* q;
LNode* r;
int j = 0;
for(p = L;j < i-1;j++){
p=p->next;
}
q=p->next;
r=q->next;
p->next = r;
free(q);
return OK;
}
printf("\n請輸入想要刪除的節點位置:");/*主函數中需要增加的部分代碼*/
scanf("%d",&a);
DeleteList(L,a);
PrintList(L);
輸入:5
2,3,4,5,6
2
4
8
2
運行結果:
算法分析:
(1)創建帶頭結點的單鏈表,首先輸入結點數,然后依次輸入各個結點的值;
(2)輸出單鏈表中的值;
(3)輸入刪除元素的位置,輸出單鏈表中的值。
算法時間復雜度:O(n)
5、循環鏈表的應用(約瑟夫回環問題)
n個數據元素構成一個環,從環中任意位置開始計數,計到m將該元素從表中取出,重復上述過程,直至表中只剩下一個元素。
提示:用一個無頭結點的循環單鏈表來實現n個元素的存儲
算法代碼:
#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
typedef struct lnode{/*結點類型定義*/
int data;
struct lnode *next;
} node, *nodeptr;
nodeptr creat() {/*創建循環單鏈表*/
nodeptr l,p, q;
int i ,n, e;
printf("please input n:" );
scanf("%d", &n);
l= (nodeptr)malloc(sizeof(node));
scanf(" %d",&e) ;
q=l;
q->data=e;
for(i=2;i<=n;i++) {
p= (nodeptr) malloc(sizeof (node));
scanf("%d" , &e) ;
p->data=e;
q->next=p;
q=p;
}
q->next=l;
return l;
}
int out (nodeptr l) {/*輸出單鏈表的元素*/
nodeptr p;
p=l;
if(!p) return 0;
printf("%3d", p->data) ;
p=p->next;
while(p!=l) {
printf("%3d", p->data) ;
p=p->next;
}
printf("\n");
}
nodeptr joseph (nodeptr l){ /*約瑟夫回環函數*/
nodeptr p,q, r;
int val, k, m;
printf(" please input m:");
scanf("%d" , &m);
p=l;k=1;
while(p->next!=p)
if (k<m){
k++;
q=p;
p=p->next;
}
else{
val=p->data;
r=p;
p=p->next;
q->next=p;
printf("the value is %d\n", val);
free(r) ;
k=1;
}
l=p;
printf("last data is:%d\n",p->data) ;
return l;
}
int main(){/*主函數*/
nodeptr l;
l=creat();/*創建循環單鏈表*/
out(l);/*輸出*/
joseph(l);/*求解約瑟夫回環問題*/
return 0;
}
輸入:5
1,7,8,6,4
5
運行結果:
6、設一帶頭結點的單鏈表,設計算法將表中值相同的元素僅保留一個結點。
提示:指針p從鏈表的第一個元素開始,利用指針q從指針p位置開始向后搜索整個鏈表,刪除與之值相同的元素;指針p繼續指向下一個元素,開始下一輪的刪除,直至p==null為至,既完成了對整個鏈表元素的刪除相同值。
#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
typedef struct lnode {/*結點類型定義*/
int data;
struct lnode *next;
} node, *nodeptr;
nodeptr creat() {/*創建帶頭結點的單鏈表*/
nodeptr l,p, q;
int i ,n, e;
l= (nodeptr) malloc (sizeof (node));
q=l;
q->next=0;
printf(" please input n: ");
scanf("%d" , &n) ;
for(i=1;i<=n;i++){
p= (nodeptr) malloc(sizeof (node));
scanf("%d", &e) ;
p->data=e;
q->next=p;
q=p;
q->next=0;
}
return l ;
}
void out (nodeptr l) { /*輸出 單鏈表的元素*/
nodeptr p;
p=l->next;
while(p) {
printf("%3d", p->data) ;
p=p->next;
printf("\n");
}
}
nodeptr delete_list (nodeptr l) { /*刪除算法,刪除值相同的結點*/
nodeptr p,q,r,s;
int j,k;
p=l->next;
while(p){
q=p->next;r=p;
while(q)
if (p->data!=q->data){
r=q;
q=q->next;
}
else{
r->next=q->next;
s=q;q=r->next;
free(s);
}
p=p->next;
}
return l;
}
int main() {/*主函數*/
nodeptr l;
l=creat();/*創建單鏈表*/
out(l) ;/*輸出*/
delete_list(l);/*調用刪除算法,刪除重復值*/
out(l) ;/*輸出*/
return 0;
}
輸入:5
1,2,3,4,5
運行結果:
四、實驗小結
通過本次實驗熟練掌握了線性表、順序表、鏈表的概念,學會了順序表以及鏈表的建立、插入元素、刪除表中某元素的等等實用的算法。同時在本次實驗中也對對這些算法進行了一定的分析,理解了順序表、鏈表數據結構的特點。此次實驗學到了很多有用的知識,也認識到了編寫代碼的不易之處,所以要加倍努力才行!