线性表【数据结构学习-青岛大学王卓老师】

https://www.bilibili.com/video/BV1qz4y1p767/

1|0线性表

1|1线性表的初始化(顺序表)

Status InitList(SqList &L) { L.elem = (ElemType *) malloc(sizeof(ElemType) * MAXSIZE); if (!L.elem) exit(OVERFLOW); L.length = 0; return OK; }

1|2线性表的销毁

void DestoryList(SqList &L) { if (L.elem) free(L.elem); L.elem = NULL; L.length = 0; }

1|3线性表的清空

void clearList(SqList &L) { L.length = 0;//将线性表的长度置为0 }

1|4线性表的长度

int GetLength(SqList L) { return L.length; }

1|5判断线性表是否为空

void isEmpty(SqList L) { if (L.length == 0)printf("顺序表为空"); else printf("顺序表不为空"); }

1|6获取元素

int GetElem(SqList L, int i, ElemType &e) { if (i < 1 || i > L.length)return ERROR; e = L.elem[i - 1]; return OK; }

1|7按值查找

int LocateElem(SqList L, ElemType e) { for (int i = 0; i < L.length; ++i) if (L.elem[i] == e)return i + 1; return 0; //查找失败 }

1|8插入

Status SqlInsert(SqList &L, int pos, ElemType e) { if (pos < 1 || pos > L.length + 1) return ERROR; if (L.length == MAXSIZE) return ERROR; for (int i = L.length - 1; i >= pos - 1; --i) { L.elem[i + 1] = L.elem[i]; } L.elem[pos - 1] = e; L.length++; return OK; }

1|9删除

Status SqlDelete(SqList &L, int pos) { if (pos < 1 || pos > L.length) return ERROR; for (int i = pos - 1; i < L.length; ++i) { L.elem[i] = L.elem[i + 1]; } L.length--; /* * for(int j =pos;j<=L.length-1;j++){ * L.elem[j-1] = L.elem[j]; * L.length--; * } * */ printf("删除成功\n"); }

1|10查看顺序表

void showList(SqList L) { printf("顺序表如下: "); for (int i = 0; i < L.length; ++i) { printf("%2d", L.elem[i]); } putchar(10); }

1|11代码

好多宏定义并没有使用

这个代码写的不太好 很多地方都是返回值,可以写成输出

基本操作是这些 还有排序 反转 等

1|0头文件SqList.h

#include <stdio.h> #include "stdlib.h" #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 #define MAXSIZE 100 typedef int Status; typedef int ElemType; typedef struct SqList{ ElemType *elem; int length; }SqList; //线性表初始化 Status InitList(SqList &L); //销毁线性表 void DestoryList(SqList &L); //清空线性表 void clearList(SqList &L); //线性表的长度 int GetLength(SqList L); //判断线性表的长度是否为空 void isEmpty(SqList L); //线性表取值 int GetElem(SqList L,int i,ElemType &e); //按值查找 int LocateElem(SqList L,ElemType e); //插入 Status SqlInsert(SqList &L,int pos,ElemType e); //删除 Status SqlDelete(SqList &L,int pos); //查看顺序表 void showList(SqList L);

1|0main.cpp

#include "SqList.h" int main() { SqList L; InitList(L); int select = 1; while (select) { printf("************************************\n"); printf("* [1] push [2] GetElem *\n"); printf("* [3] length [4] SqlDelete *\n"); printf("* [5] LocateElem [6] showList *\n"); printf("* [7] clearList [8] isEmpty *\n"); printf("* [9] destory [0] quit_sys *\n"); printf("************************************\n"); printf("请选择:>"); scanf("%d", &select); ElemType Item; int pos; if (select == 0) break; switch (select) { case 1: printf("请输入要插入的位置和数据(逗号分割):>"); scanf("%d,%d", &pos, &Item); int k; k = SqlInsert(L, pos, Item); if (k == ERROR) { printf("插入有误\n"); } else { printf("插入成功"); } break; case 2: printf("请输入获取第几个元素\n"); int i, j; scanf("%d", &i); j = GetElem(L, i, Item); if (j == ERROR) { printf("查找有误\n"); } else { printf("查找到的元素为%d\n", Item); } break; case 3: printf("线性表的长度为%d\n", GetLength(L)); break; case 4: printf("请输入要删除元素的位置:>"); scanf("%d", &pos); printf("%d", SqlDelete(L, pos)); break; case 5: printf("输入要查找的值:输出0失败\n"); scanf("%d", &Item); printf("元素在第%d个位置\n", LocateElem(L, Item)); break; case 6: showList(L); break; case 7: clearList(L); break; case 8: isEmpty(L); break; case 9: DestoryList(L); break; default: printf("输入的命令错误,请重新输入。\n"); break; } } return 0; }

1|0SqList.cpp

#include "SqList.h" Status InitList(SqList &L) { L.elem = (ElemType *) malloc(sizeof(ElemType) * MAXSIZE); if (!L.elem) exit(OVERFLOW); L.length = 0; return OK; } void DestoryList(SqList &L) { if (L.elem) free(L.elem); L.elem = NULL; L.length = 0; } void clearList(SqList &L) { L.length = 0;//将线性表的长度置为0 } int GetLength(SqList L) { return L.length; } void isEmpty(SqList L) { if (L.length == 0)printf("顺序表为空"); else printf("顺序表不为空"); } int GetElem(SqList L, int i, ElemType &e) { if (i < 1 || i > L.length)return ERROR; e = L.elem[i - 1]; return OK; } int LocateElem(SqList L, ElemType e) { for (int i = 0; i < L.length; ++i) if (L.elem[i] == e)return i + 1; return 0; //查找失败 } Status SqlInsert(SqList &L, int pos, ElemType e) { if (pos < 1 || pos > L.length + 1) return ERROR; if (L.length == MAXSIZE) return ERROR; for (int i = L.length - 1; i >= pos - 1; --i) { L.elem[i + 1] = L.elem[i]; } L.elem[pos - 1] = e; L.length++; return OK; } Status SqlDelete(SqList &L, int pos) { if (pos < 1 || pos > L.length) return ERROR; for (int i = pos - 1; i < L.length; ++i) { L.elem[i] = L.elem[i + 1]; } L.length--; /* * for(int j =pos;j<=L.length-1;j++){ * L.elem[j-1] = L.elem[j]; * L.length--; * } * */ printf("删除成功\n"); } void showList(SqList L) { printf("顺序表如下: "); for (int i = 0; i < L.length; ++i) { printf("%2d", L.elem[i]); } putchar(10); }

2|0单链表

2|1单链表的初始化

void InitList_L(LinkList &L) { L = (LinkList) malloc(sizeof(Lnode)); L->next = NULL; }

2|2链表长度

void InitList_L(LinkList &L) { L = (LinkList) malloc(sizeof(Lnode)); L->next = NULL; }

2|3取值

void GetElem_L(LinkList L, int i, ElemType &e) { LinkList p; p = L->next; int j = 1; while (p && j < i) { p = p->next; j++; } if (!p || j > i) { printf("第i个元素不存在\n"); } e = p->data; }

2|4按值查找

int LocateElem_L(LinkList L, ElemType e) { LinkList p; p = L->next; int j = 1; while (p && p->data != e) { p = p->next; j++; } if (p) { return j; } else { printf("表中没有该数据\n"); return 0; } }

2|5指定位置插入

void ListInsert_L(LinkList &L, int i, ElemType e) { Lnode *p; p = L; int j = 0; while (p && (j < i - 1)) { p = p->next; j++; } if (!p || j > i - 1) { printf("插入位置非法\n"); } Lnode *s = (Lnode*) malloc(sizeof(Lnode)); s->data = e; s->next = p->next; p->next = s; }

2|6按位置删除节点

void ListDelete(LinkList &L, int i) { LinkList p; p = L; int j = 0; while (p->next && j < i-1 ) { p = p->next; j++; } if ((!p->next) || j > i-1) { printf("删除位置不合理;\n"); } Lnode *s; s = p->next; p->next = s->next; free(s); printf("删除成功\n"); }

2|7单链表的建立

1|0头插法

//单链表的建立 1.头插法 void Create_Pushfront(LinkList &L, ElemType e) { Lnode *p = (LinkList) malloc(sizeof(Lnode)); p->data = e; p->next = L->next; L->next = p; }

1|0尾插法

书上意思是按照空表进行创建

下面的代码在不是空表的时候也可以进行插入(稍微改动)

//单链表的建立 1.尾插法 void Create_Pushback(LinkList &L, ElemType e) { LinkList r; r = L; Lnode *p = (LinkList) malloc(sizeof(Lnode)); p->data = e; p->next=NULL; while (r->next){ r=r->next; } r->next=p; r = p; }

2|8查看链表

//查看链表 void show_list(LinkList L){ Lnode *p = L->next; while (p){ printf("%d-->",p->data); p = p->next; } putchar(10); }

2|9清空链表

//清空单链表 void ClearList(LinkList &L) { Lnode *p, *q; p = L->next; while (p) { q = p->next; free(p); p = q; } L->next = NULL; }

2|10链表销毁

//链表销毁 void DestoryList(LinkList &L) { Lnode *p; while (L) { p = L; L = L->next; free(p); } }

以上代码按照青岛大学王卓老师

严蔚敏数据结构第二版书籍 学习

有些地方可以自行完善

可以自己写逆置 排序等等

3|0代码

3|1LinkList.h

#include <stdio.h> #include "stdlib.h" typedef int ElemType; typedef struct Lnode { ElemType data; struct Lnode *next; } Lnode, *LinkList; void InitList_L(LinkList &L); void isEmpty(LinkList L); void DestoryList(LinkList &L); void ClearList(LinkList &L); int ListLength_L(LinkList L); void GetElem_L(LinkList L, int i, ElemType &e); int LocateElem_L(LinkList L, ElemType e); void ListInsert_L(LinkList &L, int i, ElemType e); void ListDelete(LinkList &L,int i); void Create_Pushfront(LinkList &L, ElemType e); void Create_Pushback(LinkList &L, ElemType e); void show_list(LinkList L);

3|2LinkList.cpp

#include "LinkList.h" //初始化单链表 void InitList_L(LinkList &L) { L = (LinkList) malloc(sizeof(Lnode)); L->next = NULL; } //判断是否为空 void isEmpty(LinkList L) { if (L->next) { printf("链表不为空\n"); } else printf("链表为空\n"); } //链表销毁 void DestoryList(LinkList &L) { Lnode *p; while (L) { p = L; L = L->next; free(p); } } //清空单链表 void ClearList(LinkList &L) { Lnode *p, *q; p = L->next; while (p) { q = p->next; free(p); p = q; } L->next = NULL; } //链表长 int ListLength_L(LinkList L) { LinkList p; p = L->next; int i = 0; while (p) { i++; p = p->next; } return i; } //取第i个元素 void GetElem_L(LinkList L, int i, ElemType &e) { LinkList p; p = L->next; int j = 1; while (p && j < i) { p = p->next; j++; } if (!p || j > i) { printf("第i个元素不存在\n"); } e = p->data; } //按值查找 int LocateElem_L(LinkList L, ElemType e) { LinkList p; p = L->next; int j = 1; while (p && p->data != e) { p = p->next; j++; } if (p) { return j; } else { printf("表中没有该数据\n"); return 0; } } //第i个位置插入数据元素e void ListInsert_L(LinkList &L, int i, ElemType e) { Lnode *p; p = L; int j = 0; while (p && (j < i - 1)) { p = p->next; j++; } if (!p || j > i - 1) { printf("插入位置非法\n"); } Lnode *s = (Lnode*) malloc(sizeof(Lnode)); s->data = e; s->next = p->next; p->next = s; } //删除第i个节点 void ListDelete(LinkList &L, int i) { LinkList p; p = L; int j = 0; while (p->next && j < i-1 ) { p = p->next; j++; } if ((!p->next) || j > i-1) { printf("删除位置不合理;\n"); } Lnode *s; s = p->next; p->next = s->next; free(s); printf("删除成功\n"); } //单链表的建立 1.头插法 void Create_Pushfront(LinkList &L, ElemType e) { Lnode *p = (LinkList) malloc(sizeof(Lnode)); p->data = e; p->next = L->next; L->next = p; } //单链表的建立 1.尾插法 void Create_Pushback(LinkList &L, ElemType e) { LinkList r; r = L; Lnode *p = (LinkList) malloc(sizeof(Lnode)); p->data = e; p->next=NULL; while (r->next){ r=r->next; } r->next=p; r = p; } //查看链表 void show_list(LinkList L){ Lnode *p = L->next; while (p){ printf("%d-->",p->data); p = p->next; } putchar(10); }

3|3main.cpp

#include "LinkList.h" int main() { LinkList L; InitList_L(L); int select = 1; ElemType Item; while (select) { printf("************************************\n"); printf("* [1] pushfront [2] push_back *\n"); printf("* [3] show_list [4] ListDelete *\n"); printf("* [5] pop_front [6] GetElem_L *\n"); printf("* [7] isEmpty [8] Destory_L *\n"); printf("* [9] ClearList [10] Locate_L *\n"); printf("* [11] ListInsert [0] quit_sys *\n"); printf("************************************\n"); printf("请选择:>"); scanf("%d", &select); if (select == 0) break; switch (select) { case 1: printf("请输入要插入的数据(-1结束):>"); while (scanf("%d", &Item), Item != -1) { Create_Pushfront(L, Item); } break; case 2: printf("请输入要插入的数据(-1结束):>"); while (scanf("%d", &Item), Item != -1) { Create_Pushback(L,Item); } break; case 3: show_list(L); break; case 4: printf("输入要删除第几个元素:"); scanf("%d",&Item); ListDelete(L,Item); break; case 5: printf("表长为%d\n",ListLength_L(L)); break; case 6: printf("请输入想要取值的位置\n"); scanf("%d",&Item); int e; GetElem_L(L,Item,e); printf("第%d个元素为%d:\n",Item,e); break; case 7: isEmpty(L); break; case 8: DestoryList(L); break; case 9: ClearList(L); break; case 10: printf("请输入查找的元素\n"); scanf("%d",&Item); printf("所在位置为%d (为0表示不存在)\n",LocateElem_L(L,Item)); break; case 11: printf("请要插入的位置和元素\n"); int i ; scanf("%d%d",&Item,&i); ListInsert_L(L,Item,i); break; default: printf("输入的命令错误,请重新输入。\n"); break; } } return 0; }

写成了菜单的形式

结构体类型的定义有多种方法

定义节点

类型

定义链表 头指针 尾指针 大小

4|0循环链表

循环链表的特点:

  • 最后一个节点的指针域指向头节点,整个表链形成一个环
  • 由此,从表中任意节点出发,可以找到其他节点

和单链表很像,区别就是最后一个节点的next域指向头节点

4|1带尾指针循环链表的合并

带尾指针循环链表的合并(将Tb合并在Ta之后)

p指针指向Ta的头节点p=Ta->next;Ta->next=Tb->next->next; free(Tb->next);Tb->next=p;

LinkList Connect(LinkList Ta,LinkList Tb){ p = Ta->next; Ta->next=Tb->next->next; free(Tb.next); Tb->next=p; return Tb; }

5|0双向链表

在单链表的每个节点里再增加一个指向其直接前驱的指针域prior,这样链表中就形成了有两个方向不同的链,故称为双向链表。

5|1双链表的定义

typedef struct DuLNode{ Elemtype data; struct DuLNode *prior,*next; }DuLNode,*DuLinkList;
prior data next

1|0非空表

1|0空表

6|0双向循环链表

和单链的循环表类似,双向链表也可以有循环表

  • 让头结点的前驱指针指向链表的最后一个结点

  • 让最后一个结点的后继指针指向头结点。

1|0双向链表结构具有对称性

p->prior->next = p = p->next->prior

6|1双向链表的插入

void ListInsert_Dul(DuLinkList &L,int i,ElemType e){ if(!(p=GetElemP_DuL(L,i))) return ERROR; DuLNode *s = (DuLnode *)malloc(sizeof(DuLNode)); s->data = e; s->prior = p->prior; p->prior->next = s; s->next = p; p->prior =s; return OK; } //GetElemP_DuL(L,i)返回第i个元素的地址

6|2双向链表的删除

  • p->prior->next = p->next;

  • p->next->prior = p->prior;

void ListDelete_DuL(DuLink &L,int i,ElemType &e){ if(!(p = GetElem_P_DuL(L,i))) return ERROR; e = p->data; p->prior->next = p->next; p->next->prior = p->prior; free(p); }//ListDelete_Dul

7|0单链表、循环链表、双向链表的比较

查找 首元节点 表尾节点 节点*P的前驱节点
带头节点的点链表L L->next O(1) L->next遍历O(n) p->next 无法找到前驱
带头结点仅设头指针L的循环单链表 L->next O(1) L->next遍历O(n) p->next O(n)
带头结点仅设尾指针R的循环单链表 R->next O(1) R O(1) p->next O(n)
带头结点的双向循环链表L L->next O(1) L->prior O(1) p->prior O(1)

8|0顺序表和链表的比较

  • 链式存储结构的优点:

    • 结点空间可以动态申请和释放
    • 数据元素的逻辑次序靠结点的指针来表示,插入和删除时不需要移动数据元素。
  • 链式存储结构的缺点:

    • 存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大。

    存储密度 = 结点数据本身占用的空间/结点占用的空间总量

    一般,存储密度越大,存储空间的利用率就越高。显然顺序表的存储密度为1,而链表的存储密度小于1。

    • 链式存储结构是非随机存取结构。对于任一结点的操作都要从头指针依指针链查找到该节点,增加了算法的复杂度。

9|0线性表的应用

9|1线性表的合并

void union(List &La,List Lb){ La_len = ListLength(La); Lb_len = Listlength(Lb); for(int i = 1;i<=Lb_len;i++){ GetElem(Lb,i,e); if(!LocateElem(La,e)) ListInsert(&La,++La_len,e); } }

9|2有序表的合并

1|0顺序表实现

voigeList_Sq(SqList LA,SqList LB,SqLsit &LC){ pa = LA.elem; pb = LB.elem; LC.length = LA.length + LB.length; LC.elem = (ElemType *)malloc(sizeof(ElemType)* MAXSIZE); pc = LC.elem; pa_last = LA.elem + LA.length-1; pb_last = LB.elem + LB.length-1; while(pa <= pa_last && pb<= pb_last){ if(*pa <= *pb) *pc++ = *pa++; else *pc++ = *pb++; } while(pa <= pa_last) *pc++ = *pa++; while(pb <= pb_last) *pc++ = *pb++; }

1|0链表实现

void Merge_LinkedList(LinkList &La, LinkList &Lb, LinkList &Lc) { pa = La->next, pb = Lb->next; // pa, pb分别表示合并时所指节点 pc = Lc = La; while (pa && pb) { 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 ? pa : pb; free(Lb); }

10|0案例分析与实现

10|1多项式运算

typedef struct PloyNode{ double coeffcient; int exponent; struct PloyNode* next; }PloyNode,*PloyNomical;

同学们自己实现

10|2基于顺序存储结构的图书信息表的排序

描述

定义一个包含图书信息(书号、书名、价格)的顺序表,读入相应的图书数据完成图书信息表的创建,然后将图书按照价格降序排序,逐行输出排序后每本图书的信息。

输入

输入n+1行,前n行是n本图书的信息(书号、书名、价格),每本图书信息占一行,书号、书名、价格用空格分隔,价格之后没有空格。最后第n+1行是输入结束标志:0 0 0(空格分隔的三个0)。其中书号和书名为字符串类型,价格为浮点数类型。

输出

总计n行,每行是一本图书的信息(书号、书名、价格),书号、书名、价格用空格分隔。其中价格输出保留两位小数。

#include<stdio.h> #include<string.h> #include<malloc.h> #include<stdlib.h> #define MAXSIZE 10000//图书表可能达到的最大长度 #define OK 1 #define ERROR 0 #define OVERFLOW -2 typedef int Status; typedef struct //图书信息定义 { char no[20];//图书ISBN char name[50];//图书名字 float price;//图书价格 }Book; typedef struct { Book *elem;//存储空间的基地址 int length;//图书表中当前图书个数 }SqList;//图书表的顺序存储结构类型为SqList Status InitList_Sq(SqList &L)//构造一个空的顺序表 { L.elem=(Book * )malloc(MAXSIZE * sizeof(Book));//为顺序表分配一个大小为MAXSIZE的数组空间 if(!L.elem) exit(OVERFLOW);//存储失败 L.length=0;//空表长度为零 return OK; } Status PrintList_Sq(SqList &L) { for(int i=0;i<L.length;i++) //顺序输出每本书的信息 { printf("%s %s %.2f\n", L.elem[i].no,L.elem[i].name,L.elem[i].price);//每本书信息 // printf("%.2f\n",L.elem[i].price);//保留两位小数 } return OK; //OK=1,返回真 } Status CreationList_Sq(SqList &L,char *no,char *name,float price) { Book B; //定义B为Book strcpy(B.no,no); //复制书号 strcpy(B.name,name); B.price=price; L.elem[L.length]=B; //l的elem数组存储书的信息 L.length++; //每存好一本书,书总量自加1,l.length=l.length+1.单目运算 return OK; } Status B_Sort(SqList &L){ for (int i = 0; i <L.length ; ++i) { for (int j = 0; j < L.length -1 -i; ++j) { if (L.elem[j].price<L.elem[j+1].price){ Book temp = L.elem[j]; L.elem[j]=L.elem[j+1]; L.elem[j+1] = temp; } } } } int main() { char no[20],name[50]; float price; SqList L; InitList_Sq(L); while(scanf("%s %s %f",no,name,&price)) { if(!strcmp(no,"0")&&!strcmp(name,"0")&&price==0.0) break; CreationList_Sq(L,no,name,price); } B_Sort(L); PrintList_Sq(L); return 0; }

__EOF__

本文作者执伞候佳人
本文链接https://www.cnblogs.com/hekang520/p/17629475.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   才下眉头3  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示