数据结构期末复习知识点总结(一)——线性表,栈,队列
数据结构期末知识点总结
一. 概述数据结构期末知识点总结
-
数据结构是互相之间存在一种或多种特定关系的数据元素的集合。
-
数据结构的逻辑结构包括线性结构和非线性结构。存储结构包括顺序存储和链式存储。{
什么是逻辑结构?
简单说,逻辑结构就是数据之间的关系。而按数据之间的关系来说,逻辑结构大概可以分为两种:线性结构和非线性结构(集合、树、网)。
- 线性结构:有且只有一个开始结点和一个终端结点,并且所有结点都最多只有一个直接前驱和一个直接后继。例如:线性表,典型的线性表有:顺序表、链表、栈(顺序栈、链栈)和队列(顺序队列、链队列)。它们共同的特点就是数据之间的线性关系,除了头结点和尾结点之外,每个结点都有唯一的前驱和唯一的后继,也就是所谓的一对一的关系。
- 非线性结构:对应于线性结构,非线性结构也就是每个结点可以有不止一个直接前驱和直接后继。常见的非线性结构包括:树(二叉树)、图(网)等。
什么是存储结构?
逻辑结构指的是数据间的关系,而存储结构是逻辑结构的存储映像。通俗的讲,可以将存储结构理解为逻辑结构用计算机语言的实现。常见的存储结构有顺序存储、链式存储、索引存储以及散列存储(哈希表)。
- 顺序存储:把逻辑上相邻的节点存储在物理位置上相邻的存储单元中,结点之间的逻辑关系由存储单元的邻接关系来体现。由此得到的存储结构为顺序存储结构,通常顺序存储结构是借助于数组来描述的。优点:节省空间,可以实现随机存取;缺点:插入、删除时需要移动元素,效率低。
- 链式存储:在计算机中用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。特点是元素在物理上可以不相邻,所以每个数据元素包括了一个数据域和一个指针域,数据域用来存放数据,而指针域用来指向其后继结点的位置。优点:插入、删除灵活;缺点:不能随机存取,查找速度慢。
}

-
数据项是数据的最小单位,数据元素是数据的基本单位{
数据元素是组成数据的、有一定意义的基本单位,在计算机中通常作为整体处理,也称为记录(元组、结点、顶点)。
数据项(属性、字段)
- 一个数据元素可以由若干个数据项组成。
- 数据项是数据不可分割的最小单位。
}
-
数据的逻辑结构是指数据元素之间逻辑关系的整体
eg.以下数据结构中____属非线性结构。
A.栈
B.串
C.队列
D.平衡二叉树
答:栈、串和队列中元素之间的关系均为线性关系,平衡二叉树属树形结构。本题答案为D。
eg.以下属于逻辑结构是_____。
A.顺序表
B.哈希表
C.有序表
D.单链表
答:顺序表、单链表和哈希表都属于存储结构,只有有序表属于逻辑结构。本题答案为C
eg.以下不属于存储结构是_____。
A.栈
B.线索树
C.哈希表
D.双链表
答:栈属于一种逻辑结构,通常有顺序栈和链栈两种存储结构。本题答案为A。
二. 线性表
1.单链表(带头节点)
不带头节点的只是头指针不指向没有实际意义的节点而已,初始化为NULL
单链表的结构
typedef struct Node{
int data;
Node *next;
}Node;
初始化
Node* init(){
Node* head=(Node*)malloc(sizeof(Node));//带头节点
// LinkedList() : head(nullptr) {} //不带头节点
head->data=0;
head->next=NULL;
return head;
}
头插法
head_insert(Node* list,int n){
Node *addlist=init();
addlist->data=n;
addlist->next=list->next;
list->next=addlist;
}
尾插法
tail_insert(Node* list,int n){
Node* addlist=init();
Node* tailnode=get_tail(list);
addlist->data=n;
tailnode->next=addlist;
addlist->next=NULL;
}
删除
del(Node* list,int position){
Node* temp=list;
for(int i=0;i<position-1;i++){
temp=temp->next;
}
//q指向要删除的节点
Node *q=temp->next;
//让要删除的节点的前驱指向要删除节点的后继
temp->next=q->next;
free(q);
}
释放链表
free_list(Node* list){
Node* p=list->next;
Node* q;
while(p!=NULL){
q=p->next;
free(p);
p=q;
}
list->next=NULL;
}
单链表的应用--反转链表
Node* reverseList(Node* head){
Node* first=NULL;
Node* second=head->next;
Node* third=NULL;
while(second!=NULL){
third=second->next;
second->next=first;
first=second;
second=third;
}
Node* hd=init();
hd->next=first;
return hd;
}
void ReverseList(LinkList &L) {
LinkList p = L->next, q;
L->next = ___NULL___;
while (p != NULL) {
q = p->next;
p->next = ___L->next___;
L->next = p;
p = q;
}
}
2.双链表(带头节点)
双向链表结构
typedef struct Node{
Node* prev;
int data;
Node* next;
}Node;
初始化
Node* init(){
Node* head=(Node*)malloc(sizeof(Node));
head->data=0;
head->next=NULL;
head->prev=NULL;
}
头插法
void insertHead(Node* list,int e){
Node* newNode=init();
newNode->data=e;
newNode->prev=list;
newNode->next=list->next;
if(list->next!=NULL){
list->next->prev=newNode;
}
list->next=newNode;
}
尾插法
void insertTail(Node* list,int e){
Node* newNode=init();
newNode->data=e;
while(list->next!=NULL){
list=list->next;
}
list->next=newNode;
newNode->prev=list;
}
删除节点
void del(Node* list,int pos){
for(int i=0;i<pos-1;i++){
list=list->next;
}
Node* temp=list->next;
list->next=temp->next;
list->next->prev=temp;
free(temp);
}
3.循环单链表(带头节点)
结构定义
typedef struct Node {
int data;
Node* next;
} Node;
初始化
Node* init() {
Node* head = (Node*)malloc(sizeof(Node));
head->data = 0;
head->next = head; // 指向自己形成循环
return head;
}
头插法
void head_insert(Node* list, int n) {
Node* addlist = (Node*)malloc(sizeof(Node));
addlist->data = n;
addlist->next = list->next;
list->next = addlist;
}
尾插法
void tail_insert(Node* list, int n) {
Node* addlist = (Node*)malloc(sizeof(Node));
Node* tail = list;
while (tail->next != list) {
tail = tail->next;
}
addlist->data = n;
addlist->next = list; // 新节点指向头节点
tail->next = addlist;
}
删除节点
void del(Node* list, int position) {
Node* temp = list;
for (int i = 0; i < position; i++) {
temp = temp->next;
if (temp == list) return; // 越界处理
}
Node* q = temp->next;
temp->next = q->next;
free(q);
}
释放链表
void free_list(Node* list) {
Node* p = list->next;
while (p != list) {
Node* q = p->next;
free(p);
p = q;
}
list->next = list; // 恢复空链表状态
}
4.循环双链表(带头节点)
结构定义
typedef struct DNode {
int data;
DNode* prior;
DNode* next;
} DNode;
初始化
DNode* init() {
DNode* head = (DNode*)malloc(sizeof(DNode));
head->prior = head;
head->next = head;
return head;
}
头插法
void head_insert(DNode* list, int n) {
DNode* addlist = (DNode*)malloc(sizeof(DNode));
addlist->data = n;
addlist->next = list->next;
addlist->prior = list;
list->next->prior = addlist;
list->next = addlist;
}
尾插法
void tail_insert(DNode* list, int n) {
DNode* addlist = (DNode*)malloc(sizeof(DNode));
DNode* tail = list->prior; // 直接获取尾节点
addlist->data = n;
addlist->next = list;
addlist->prior = tail;
tail->next = addlist;
list->prior = addlist;
}
删除节点
void del(DNode* list, int position) {
DNode* p = list->next;
for (int i = 0; i < position && p != list; i++) {
p = p->next;
}
if (p == list) return; // 越界处理
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
}
释放链表
void free_list(DNode* list) {
DNode* p = list->next;
while (p != list) {
DNode* q = p->next;
free(p);
p = q;
}
list->next = list;
list->prior = list;
}
反转链表
void ReverseList(DNode* &L) {
DNode *p = L->next, *q;
L->next = L; // 断开原链接
L->prior = L;
while (p != L) {
q = p->next;
// 将p插入到新链表头部
p->next = L->next;
p->prior = L;
L->next->prior = p;
L->next = p;
p = q;
}
}
三.栈和队列
1.栈的顺序结构
栈的顺序结构
typedef struct stack{
int data[MAX_SIZE];
int top;
}Stack;
初始化
void init(Stack* st){
st->top=-1;
}
初始化(动态分配内存空间)
Stack* init2(){
Stack* st=(Stack*)malloc(sizeof(Stack));
st->top=-1;
}
判读是否为空
int isEmpty(Stack* st){
if(st->top!=-1){
return 0;
}else{
return 1;
}
}
压栈
int push(Stack* st,int e){
if(st->top>=MAX_SIZE-1){
printf("满了\n");
return 0;
}
st->top++;
st->data[st->top]=e;
}
出栈
int pop(Stack* st){
if(!isEmpty){
printf("栈空\n");
return 0;
}
int x=st->data[st->top];
st->top--;
return x;
}
查看栈顶元素
void peek(Stack* st){
printf("栈顶元素为%d\n",st->data[st->top]);
}
2.栈的链式结构
栈的链式结构(带头节点)
typedef struct stack{
int data;
stack* next;
}Stack;
栈的初始化
Stack* init(){
Stack* st=(Stack*)malloc(sizeof(Stack));
st->next=NULL;
st->data=0;
}
判断是否为空
int isempty(Stack *st){
if(st->next==NULL){
printf("栈空\n");
return 1;
}else{
return 0;
}
}
压栈 头插法
void push(Stack* st,int e){
Stack* addNode=(Stack*)malloc(sizeof(Stack));
addNode->data=e;
addNode->next=st->next;
st->next=addNode;
}
出栈
int pop(Stack* st){
if(st->next==NULL){
printf("栈空\n");
return 0;
}
Stack* temp=st->next;
st->next=temp->next;
int x=temp->data;
free(temp);
return x;
}
查看栈顶元素
void peek(Stack* st){
printf("栈顶元素为%d\n",st->next->data);
}
3.队的顺序结构(循环队列)
队的顺序结构
typedef struct{
ElemType data[MAX_SIZE];
int front;
int rear;
}Queue;
初始化
void init(Queue *q){
q->front=0;
q->rear=0;
}
判断队是否为空
int isempty(Queue *q){
if(q->front==q->rear){
printf("队为空\n");
return 0;
}else return 1;
}
出队
ElemType dequeue(Queue *q){
if(q->front==q->rear){
printf("队为空");
return 0;
}
ElemType e=q->data[q->front];
q->front=(q->front+1)%MAX_SIZE;
return e;
}
入队
int enqueue(Queue *q,ElemType e){
if((q->rear+1)%MAX_SIZE==q->front){
printf("队满\n");
return 0;
}
q->data[q->rear]=e;
q->rear=(q->rear+1)%MAX_SIZE;
return 1;
}
4.队的链式结构
队的链式结构
typedef struct QueueNode{
int data;
struct QueueNode* next;
}QueueNode;
typedef struct{
QueueNode* front;
QueueNode* rear;
}Queue;
初始化
Queue* init(){
Queue* q=(Queue*)malloc(sizeof(Queue));
QueueNode* node=(QueueNode*)malloc(sizeof(QueueNode));
node->data=0;
node->next=NULL;
q->front=node;
q->rear=node;
return q;
}
判断是否为空
int isempty(Queue *q){
if(q->front==q->rear){
printf("队为空\n");
return 1;
}
return 0;
}
入队 尾插法
void enqueue(Queue* q,int e){
QueueNode* addnode=(QueueNode*)malloc(sizeof(QueueNode));
addnode->data=e;
addnode->next=NULL;
q->rear->next=addnode;
q->rear=addnode;
}
出队
int dequeue(Queue* q){
QueueNode* temp=q->front->next;
int x=temp->data;
q->front->next=temp->next;
//若删除的是最后一个元素,让队尾对头重新指向头节点
if(q->rear==temp){
q->rear=q->front;
}
free(temp);
return x;
}
浙公网安备 33010602011771号