声明:大部分内容来自 - 《2019天勤数据结构高分笔记》
1. 顺序表:
1.1 初始化顺序表
void init(sqlist &L) //初始化有个递增的顺序表,L要改变,所以用引用型
{
L.length = 0;
}
1.2 查找
(1) 查找位置
int findElem(sqlist L,int x)
{
int length = L.length;
int i;
for(i = 0; i < length; i++)
{
if(L.data[i] > x)
return i;
}
return i;
}
(2)查找元素值为e的位置
int findElem(sqlist L, int e)
{
int i;
for(i = 0; i < L.length; i++ )
{
if(L.data[i] == e)
return i;
}
return -1;
}
(3)查找位置p的元素
重点是判断位置p是否合理
int getElem(sqlist L, int p, int &e)
{
if(p<0 || p>=L.length)
{
printf("位置错误!\n");
return 0;
}
e = L.data[p];
}
1.3 一顺序表L,其中元素递增,设计算法使 插入一元素x(int型)后仍有序。
思路:1找到要插入位置p + 2进行插入操作
初始化 + 遍历 + 判满 + 插入 + 输出数组详请
完整版:
#include<bits/stdc++.h>
#define maxsize 100
using namespace std;
typedef struct sqlist
{
int data[maxsize];
int length;
}sqlist;
void init(sqlist &L) //初始化有个递增的顺序表,L要改变,所以用引用型
{
L.data[0] = 1;
L.data[1] = 3;
L.data[2] = 5;
L.length = 3;
}
int findElem(sqlist L,int x)
{
int length = L.length;
int i;
for(i = 0; i < length; i++)
{
if(L.data[i] > x)
return i;
}
return i;
}
int isfull(sqlist L)
{
if(L.length >= maxsize)
return 0;
return 1;
}
void trace(sqlist L)
{
int i;
printf("顺序表:");
for(i = 0; i < L.length ;i++)
printf("%d ",L.data[i]);
cout<<endl<<endl;
}
void insert(sqlist &L,int x) //L要改变,所以用引用型
{
int p = findElem(L,x);
int i;
for(i = L.length-1; i>=p ;i--)
L.data[i+1] = L.data[i];
L.data[p] = x;
L.length++;
printf("插入成功!\n");
trace(L);
}
int main()
{
int x;
sqlist L;//定义一个循序表L
init(L); //初始化
trace(L);//遍历
while(L.length < maxsize)
{
int f = isfull(L); //判断是否已满
if( f = 1)
{
printf("输入要插入的元素整数x:");
scanf("%d",&x);
insert(L,x);
}
else
printf("顺序表已满!\n");
}
return 0;
}
int findElem(sqlist L, int e)
{
int i;
for(i = 0; i < L.length; i++ )
{
if(L.data[i] == e)
return i;
}
return -1;
}
1.4 删除顺序表中下标为p的元素,成功返回1,失败返回0,被删除元素值复制给e
#include<bits/stdc++.h>
#define maxsize 100
using namespace std;
typedef struct sqlist
{
int data[maxsize];
int length;
}sqlist;
void init(sqlist &L) //初始化有个递增的顺序表,L要改变,所以用引用型
{
L.data[0] = 1;
L.data[1] = 3;
L.data[2] = 5;
L.length = 3;
}
int findElem(sqlist L,int x)
{
int length = L.length;
int i;
for(i = 0; i < length; i++)
{
if(L.data[i] > x)
return i;
}
return i;
}
void trace(sqlist L)
{
int i;
printf("顺序表:");
for(i = 0; i < L.length ;i++)
printf("%d ",L.data[i]);
cout<<endl<<endl;
}
int del(sqlist &L, int p, int &e)
{
int i;
e = L.data[p];
for(i = p; i < L.length; i++)
{
L.data[i] = L.data[i+1];
}
L.length--;
return 1;
}
int main()
{
int x,e,p;
sqlist L;//定义一个循序表L
init(L); //初始化
trace(L);//遍历
while(L.length > 0)
{
printf("输入位置p:");
scanf("%d",&p);
del(L,p,e);
trace(L);
}
return 0;
}
2. 链表:
头结点:它一定是第一个结点,且值域是空
链表可分两类:1 带有头结点,2 不带头结点
头结点的好处:
1 头插法容易实现
2 一些条件判断不用去考虑 空链表 和 非空链表
5类链表:
1 单链表
2 双链表
3 循环单链表
4 循环双链表
5 静态链表(数组表示)
以下链表均带有头结点:
2.1 判空
无头结点均:
head == NULL;
2.1.1 单链表 and 双链表
有头结点head:
head -> next == NULL;
2.1.2 循环链表
有头结点:
head == head -> next;
2.1.3 循环双链表
有头结点:
下面4行代码,任一1个均可判断
head == head -> prior ;
head == head -> next ;
head == head -> next || head == head -> prior ;
head == head -> next && head == head -> prior ;
2.2 两个单链表A、B(均带头结点),元素均有序递增,设计算法,将A、B合并为链表C,C由A和B结点组成。
扩展:随机数生成
#include<bits/stdc++.h>
using namespace std;
void myrand()
{
int i;
for(i = 0; i < 10; i++)
printf("%d ", rand()%10);
cout<<endl<<endl;
}
int main(void)
{
srand(time(NULL));
myrand();
myrand();
return 0;
}
该题思路:
1 定义链表结构
2 随机数预处理
3 初始化单链表
4 创建单链表,且结点的值非减,将详情输出,用尾插法(还有头插法,本文后面会有!)
5 合并两个单链表,也用尾插法(还有头插法,本文后面会有!)
6 讲合并的单链表详情输出
完整代码:
#include<bits/stdc++.h>
#define num 100
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}*Link,LNode;
void init(LNode *&L)
{
L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;
}
void creat(LNode *&L) // Link L 等价于 LNode *L
{
LNode *q,*p=L;
int length = rand()%num;
int i,j;
q = (LNode *)malloc(sizeof(LNode));
j = rand()%num;
while(j > num/6) //一开始就是很大的数,不太好,我希望数字可以分布均匀一点,这里j是最后的尾结点!
{
j = rand()%num;
}
q->data = j;
p->next = q;
p = q;
for(i = 0; i < length; i++)
{
q = (LNode *)malloc(sizeof(LNode));
j = rand()%num;
while(j < p->data)
{
j = rand()%num;
}
q->data = j;
p->next = q;
p = q;
}
p->next = NULL;
printf("创建成功!\n");
}
void trace(LNode *L)
{
LNode *p = L->next;
if(p)
{
while(p)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
else
printf("链表为空!\n");
}
void merge(Link A, Link B,Link &C)
{
Link p = A->next;
Link q = B->next;
Link r;
free(B);
C = A;
C->next = NULL;
r = C;
while(p&&q)
{
if(p->data > q->data)
{
r->next = q;
q = q->next;
r = r->next;
}
else
{
r->next = p;
p = p->next;
r = r->next;
}
}
if(p)
{
r->next = p;
}
else
r->next = q;
printf("成功!\n");
}
int main()
{
srand(time(NULL));
Link A,B,C;
init(A);
init(B);
init(C);//初始化
printf("链表A");
creat(A);
printf("\n链表B");
creat(B);
printf("\n链表A:\n");
trace(A);
printf("\n链表B:\n");
trace(B);
printf("\n链表A和链表B合并为链表C ");
merge(A, B, C);
printf("\n链表C:\n");
trace(C);
return 0;
}
2.2.1 创建单链表 之尾插法
一直在尾巴末尾添加结点,当添加一个结点时,注意谁是新的尾节点
关键代码:
q->data = j;
p->next = q;
p = q;
完整代码见上题
2.2.2 创建单链表 之头插法
一直在头结点后面插入结点
关键代码:
q->data = j;
q->next = p->next;
p->next = q;
完整代码:
#include<bits/stdc++.h>
#define num 100
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}*Link,LNode;
void init(LNode *&L)
{
L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;
}
void creat(LNode *&L) // Link L 等价于 LNode *L
{
LNode *q, *p=L;
int length = rand()%num;
int i,j;
q = (LNode *)malloc(sizeof(LNode));
j = rand()%num;
while(j < 5*num/6) //一开始就是很小的数,不太好,我希望数字可以分布均匀一点
{
j = rand()%num;
}
q->data = j;
q->next = NULL;
p->next = q;
for(i = 1; i < length; i++)
{
q = (LNode *)malloc(sizeof(LNode));
j = rand()%num;
while(j > p->next->data)
{
j = rand()%num;
}
q->data = j;
q->next = p->next;
p->next = q;
}
printf("创建成功!\n");
}
void trace(LNode *L)
{
LNode *p = L->next;
if(p)
{
while(p)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
else
printf("链表为空!\n");
}
int main()
{
srand(time(NULL));
Link A;
init(A);
printf("链表A");
creat(A);
printf("\n链表A:\n");
trace(A);
return 0;
}
2.2.3 删除结点
2.2.3.1 单链表删除第n个结点
删除结点p后一个结点q,而非结点p
关键
p->next = q->next;
更好的版本:
p->next = q->next;
free(q);
完整代码:
#include<bits/stdc++.h>
#define num 100
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}*Link,LNode;
void init(LNode *&L)
{
L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;
}
void creat(LNode *&L) // Link L 等价于 LNode *L
{
LNode *q,*p=L;
int length = rand()%num;
int i,j;
q = (LNode *)malloc(sizeof(LNode));
j = rand()%num;
while(j > num/6) //一开始就是很大的数,不太好,我希望数字可以分布均匀一点
{
j = rand()%num;
}
q->data = j;
p->next = q;
p = q;
for(i = 0; i < length; i++)
{
q = (LNode *)malloc(sizeof(LNode));
j = rand()%num;
while(j < p->data)
{
j = rand()%num;
}
q->data = j;
p->next = q;
p = q;
}
p->next = NULL;
printf("创建成功!\n");
}
void del(Link &L, int e)
{
LNode *p = L->next, *q, *r = L;
int flag = 0,i = 1;
while(p)
{
if(i == e)
{
q = p;
r->next = p->next;
free(q);
flag = 1;
printf("\n第%d个结点已被删除!\n", e);
break;
}
i++;
p = p->next;
r = r->next;
}
if( flag == 0)
printf("位置越界!\n");
}
void trace(LNode *L)
{
LNode *p = L->next;
if(p)
{
while(p)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
else
printf("链表为空!\n");
}
int main()
{
int e;
srand(time(NULL));
Link L;
init(L);
printf("链表L");
creat(L);
printf("\n链表L:");
trace(L);
e = rand()%10 + 1;
del(L, e);
printf("\n链表L:");
trace(L);
return 0;
}
注意:这里删除操作分情况,有不同思路的代码:
1 删除第n个结点,那么每次查找结点要计数累加即可,再判断是否越界
2 删除结点值为n的结点,是删除第一个这样的结点(1个) 还是 所有的值为n的结点(2个及以上),判断一下是否存在这样的结点(0个),见下面的例子:
2.2.3.2 单链表删除值为n的结点
完整代码:
#include<bits/stdc++.h>
#define num 100
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}*Link,LNode;
void init(LNode *&L)
{
L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;
}
void creat(LNode *&L) // Link L 等价于 LNode *L
{
LNode *q,*p=L;
int length = rand()%num;
int i,j;
q = (LNode *)malloc(sizeof(LNode));
j = rand()%num;
while(j > num/6) //一开始就是很大的数,不太好,我希望数字可以分布均匀一点
{
j = rand()%num;
}
q->data = j;
p->next = q;
p = q;
for(i = 0; i < length; i++)
{
q = (LNode *)malloc(sizeof(LNode));
j = rand()%num;
while(j < p->data)
{
j = rand()%num;
}
q->data = j;
p->next = q;
p = q;
}
p->next = NULL;
printf("创建成功!\n");
}
void del(Link &L, int e)
{
LNode *p = L->next, *q, *r = L;
int flag = 0,i = 1;
while(p)
{
if(p->data == e)
{
q = p;
r->next = p->next;
free(q);
flag = 1;
printf("\n值为%d的结点已被删除!\n", e);
break;
}
i++;
p = p->next;
r = r->next;
}
if( flag == 0)
printf("无值为%d的结点!\n",e);
}
void trace(LNode *L)
{
LNode *p = L->next;
if(p)
{
while(p)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
else
printf("链表为空!\n");
}
int main()
{
int e;
srand(time(NULL));
Link L;
init(L);
printf("链表L");
creat(L);
printf("\n链表L:");
trace(L);
e = rand()%10 + 1;
del(L, e);
printf("\n链表L:");
trace(L);
return 0;
}
两个代码的不同之处 仅仅在于 条件判断:
while( p)后面的:
删除第n个结点:
if(i == e)
删除值为n的结点:
if(p->data == e)
2.3 双链表
2.3.1.1 尾插法创建双链表
void creat(DLink &L) //尾插法
{
DLink p = L, q;
int length = rand()%num ; // 双链表长度
int i ;
for( i = 0; i < length; i++ )
{
q = (DLink)malloc(sizeof(DLNode));
q->data = rand()%num;
q->next = NULL;
q->prior = p;
p->next = q;
p = q;
}
cout << "创建成功!" << endl << endl;
}
2.3.1.2 头插法创建双链表
void creat2(DLink &L) //头插法
{
DLink p = L, q;
int length = rand()%num;
int i;
cout << "随机生成:" ;
for( i = 0; i < length; i++ )
{
q = (DLink)malloc(sizeof(DLNode));
q->data = rand()%num;
cout << q->data << " ";
q->next = p->next;
if(p->next)
p->next->prior = q;
q->prior = p;
p->next = q;
}
cout << endl << "头插法创建成功!" << endl;
}
2.3.2 查找双链表第一个值为n的结点
void findElem(DLink L, int e)
{
DLink p = L->next;
int flag = 0, i = 1;
while(p)
{
if(p->data == e)
{
flag = 1;
break;
}
p = p->next;
i++;
}
if( flag == 1)
cout << "第" << i << "个结点是结点值为" << e << "的结点" << endl;
else
cout << "无结点值为" << e << "的结点" << endl;
}
2.3.3 双链表第n个结点后插入一个结点
void insert(DLink L, int n, int e) //在第n个结点后 插入 结点值为e 的结点
{
DLink p = L->next, q;
int i = 1;
int length = getlength(L);
if(length < n || n < 1)
{
cout << "位置越界!" << endl;
}
else
{
while(i < n)
{
p = p->next;
i++;
}
q = (DLink)malloc(sizeof(DLNode));
q->data = e;
q->next = p->next;
p->next->prior = q;
p->next = q;
q->prior = p;
cout << "插入成功!" << endl;
}
}
2.3.2 删除双链表第一个值为n的结点
void delElem(DLink L, int e)
{
DLink p = L->next, q = L;
int flag = 0 , i =1;
while(p)
{
if(p->data == e)
{
flag = 1;
q->next = p->next;
p->next->prior = q;
cout << "第" << i << "个结点,其值为" << e <<",已被删除!" << endl;
break;
}
q = q->next;
p = p->next;
i++;
}
if( flag == 0)
cout << "无结点值为" << e << "的结点!" << endl;
}
上面4部分可运行的完整代码:
https://paste.ubuntu.com/p/gGyCPWmrH3/
或
https://blog.csdn.net/qq_40893824/article/details/105890799(防网站中上面代码丢失)
运行结果:
2.4 循环链表
仅单循环链表:
尾结点的判断条件:
p - > next == head;
完整的代码:
#include<bits/stdc++.h>
#define num 100
using namespace std;
typedef struct Node
{
int data;
struct Node *next;
}*Link,Node;
void init(Link &L)
{
L = (Link)malloc(sizeof(Node));
L->next = L;
cout << "初始化成功!" << endl;
}
void mycout(int n)
{
int i = 0;
for(i = 0; i < n; i++)
cout << endl;
}
void creat(Link &L)
{
Link p = L,q;
int length = rand()%num;
int i;
cout << "随机数:" << endl;
for(i = 0; i < length; i++)
{
q = (Link)malloc(sizeof(Node));
q->data = rand()%num;
cout << q->data << " ";
q->next = L->next;
L->next = q;
L = q;
}
cout << endl << "创建成功!" << endl;
}
void trace(Link L)
{
Link p = L->next->next;
while(p != L)
{
cout << p->data << " " ;
p = p->next;
}
cout << p->data ;
cout << endl;
}
int main()
{
srand(time(NULL));
Link L;
int n;
cout << "循环链表L" ;
init(L);
mycout(1);
cout << "循环链表L" ;
creat(L);
mycout(1);
cout << "循环链表L元素:" ;
trace(L);
return 0;
}
这里仅写循环链表的创建,插入和删除完全可以参考之前单链表的操作。