自学内容网 自学内容网

数据结构-c++

链表

设计链表

#include <iostream>
using namespace std;

struct linknode
{
int val;
linknode* next;
linknode(int val):val(val),next(NULL){};
};
linknode* _dummyhead;// 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
int _size;//链表的大小

//初始化链表 
void init()
{
_dummyhead=new linknode(0);
_size=0;
}

//获取第index个节点的值 ,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
int get(int index)
{
if(index>=_size||index<0)
{
return -1;
}
linknode* cur=_dummyhead->next;
while(index--)
{
cur=cur->next;
}
return cur->val;
}

 // 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
void addh(int val)
{
linknode *newnode=new linknode(val);
newnode->next=_dummyhead->next;
_dummyhead->next=newnode;
_size++;
} 

// 在链表最后面添加一个节点
void adde(int val)
{
linknode* newnode =new linknode(val);
linknode* cur=_dummyhead;
while(cur->next!=NULL)
{
cur=cur->next;
}
cur->next=newnode;
_size++;
} 


// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果index大于链表的长度,则返回空
// 如果index小于0,则在头部插入节点
void addi(int index,int val)
{
if(index>_size)return;
if(index<0)index=0;
linknode* newnode=new linknode(val);
linknode* cur=_dummyhead;
while(index--)
{
cur=cur->next;
} 
newnode->next=cur->next;
cur->next=newnode;
_size++;
}

//删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的
void deletei(int index)
{
if(index>=_size||index<0)
{
return ;
}
linknode* cur = _dummyhead;
    while (index--) 
{
        cur = cur->next;
    }
linknode* tmp=cur->next;
cur->next=cur->next->next;
delete tmp;
tmp=NULL;
_size--;
}

//打印链表 
void printlist()
{
linknode* cur=_dummyhead;
while(cur->next!=NULL)
{
cout<<cur->next->val<<" ";
cur=cur->next;
}
cout<<endl;
}
int main()
{

return 0;
}

1.进制转换

1.设计一个算法,用带头结点的单链表实现非负十进制整数转二进制数。

思路:通过头插法这样我们在进行进制转换时就不用reverse了

#include <iostream>
using namespace std;
struct linknode
{
    int digit;  // 存储二进制的每一位
    linknode* next;
    linknode(int digit) :digit(digit), next(NULL) {}
};
linknode* _dummyhead=new linknode(0);//虚拟头节点
// 十进制数转二进制数的函数
void transform(int n)
{
    if (n < 0)
    {
        cout << 0;
        return;
    }
    while (n>0)
    {
        int remainder = n % 2;//获取余数
        linknode* newnode = new linknode(remainder);
        newnode->next = _dummyhead->next;
        _dummyhead->next = newnode;
        n /= 2;
    }
}
// 输出链表的内容(即二进制位)
void print()
{
    linknode* cur = _dummyhead;
    while (cur->next !=NULL)
    {
        cur = cur->next;
        cout << cur->digit;
    }
}
int main()
{
    int n;
    cin >> n;
    transform(n);
    print();
    return 0;
}

2.顺序表逆置

2.设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为 O(1)。

#include <iostream>
using namespace std;
#define MAXLEN 100
typedef int datatype;
// 顺序表结构定义
struct seqlist 
{
    datatype data[MAXLEN];  // 存储顺序表的元素
    int Length;             // 顺序表的当前长度
};
// 逆置顺序表的函数
void reverseList(seqlist& L) 
{
    int left = 0;                // 左指针,指向顺序表的开始
    int right = L.Length - 1;    // 右指针,指向顺序表的末尾
    while (left < right) 
    {
        // 交换L.data[left]和L.data[right]
        swap(L.data[left], L.data[right]);
        // 移动指针
        left++;
        right--;
    }
}
// 打印顺序表的函数
void printList(const seqlist& L) 
{
    for (int i = 0; i < L.Length; i++) 
    {
        cout << L.data[i] << " ";
    }
    cout << endl;
}
int main() 
{
    seqlist L = { {1, 2, 3, 4, 5}, 5 };  // 顺序表元素为1, 2, 3, 4, 5,长度为5
    cout << "原顺序表:";
    printList(L);  // 输出原顺序表
    reverseList(L);  // 逆置顺序表
    cout << "逆置后的顺序表:";
    printList(L);  // 输出逆置后的顺序表
    return 0;
}

3.链表转置

思路
首先定义一个cur指针,指向虚拟头结点的下一个节点,再定义一个pre指针,初始化为null。

然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。

为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。

最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们_dummyhead->next = pre; 就可以了,pre指针就指向了新的头结点。

#include <iostream>
using namespace std;
struct linknode
{
    int val;  
    linknode* next;
    linknode(int val) :val(val), next(NULL) {}
};
linknode* _dummyhead = new linknode(0);//虚拟头节点
// 在链表尾插入节点
void adde(int val)
{
    linknode* newnode = new linknode(val);
    linknode* cur =_dummyhead;
    while (cur->next != NULL)
    {
        cur = cur->next;
    }
    cur->next = newnode;
    newnode->next = NULL;
}
void reverselist()
{
    linknode* cur = _dummyhead->next;
    linknode* temp; // 保存cur的下一个节点
    linknode* pre = NULL;
    while (cur!=NULL)
    {
        temp = cur->next;// 保存一下 cur的下一个节点,因为接下来要改变cur->next
        cur->next = pre;// 翻转操作
        // 更新pre 和 cur指针
        pre = cur; 
        cur = temp;
    }
    _dummyhead->next = pre;  // 将头结点的next指向反转后的链表头
}
// 打印链表
void print() 
{
    linknode* cur = _dummyhead;
    while (cur->next != NULL) 
    {
        cout << cur->next->val << " ";
        cur = cur->next;
    }
    cout << endl;
}
int main()
{
    adde(1);
    adde(2);
    adde(3);
    adde(4);
    adde(5);
    // 输出原链表
    cout << "原链表: ";
    print();
    // 逆置链表
    reverselist();
    // 输出逆置后的链表
    cout << "逆置后的链表: ";
    print();
    return 0;
}

栈的实现

#include <iostream>

using namespace std;


const int N = 100;
// 假设栈的初始化、入栈、出栈和栈空判断等基本操作已经实现

// 栈的结构定义
struct seqstack {
    int data[N];  // 栈的存储空间
    int top;        // 栈顶指针
};

// 初始化栈
void init(seqstack* s) {
    s->top = -1;
}

// 入栈操作
void push(seqstack* s, int x) {
    if (s->top < N) {  // 防止栈溢出
        s->top++;
        s->data[s->top] = x;
    }
}

// 出栈操作
bool pop(seqstack* s, int& x) {
    if (s->top == -1) return false;  // 栈为空,无法出栈
    x = s->data[s->top];
    s->top--;
    return true;
}

// 栈空判断
bool empty(seqstack* s) {
    return s->top == -1;
}

// 非负十进制整数转八进制数
void transform(int n) {
    seqstack s;
    init(&s);

    // 特殊情况:如果n为0,直接输出0
    if (n == 0) {
        cout << 0 << endl;
        return;
    }

    // 进行转换
    while (n > 0) {
        push(&s, n % 8);  // 余数入栈
        n = n / 8;        // 更新n为商
    }

    // 弹出栈内元素并输出,得到八进制数
    while (!empty(&s)) {
        int digit;
        pop(&s, digit);
        cout << digit;
    }
    cout << endl;
}

int main() {
    int decimalNum;
    cout << "请输入一个非负十进制整数: ";
    cin >> decimalNum;

    cout << "该整数的八进制表示为: ";
    transform(decimalNum);

    return 0;
}

队列

队列实现

#include <iostream>
using namespace std;

#define maxsize 50
typedef int datatype;

typedef struct {
    datatype data[maxsize];
    int front;
    int rear;
} sqqueue;

// 初始化队列
void initque(sqqueue &q) {
    q.rear = q.front = 0;
}

// 判断队列是否为空
bool isempty(sqqueue &q) {
    return q.front == q.rear;
}

// 入队操作
bool enqueue(sqqueue &q, datatype x) {
    if ((q.rear + 1) % maxsize == q.front) {
        return false; // 队列满
    }
    q.data[q.rear] = x;
    q.rear = (q.rear + 1) % maxsize;
    return true;
}

// 出队操作
bool dequeue(sqqueue &q, datatype &x) {
    if (isempty(q)) {
        return false; // 队列空
    }
    x = q.data[q.front];
    q.front = (q.front + 1) % maxsize;
    return true;
}

// 获取队列大小
int que_size(sqqueue &q) {
    return (q.rear + maxsize - q.front) % maxsize;
}

// 显示队列内容
void showqueue(sqqueue &q) {
    int p = q.front;
    if (isempty(q)) {
        cout << "队空" << endl;
        return;
    }
    while (p != q.rear) {
        cout << q.data[p] << " ";
        p = (p + 1) % maxsize;
    }
    cout << endl;
}

int main() {
    sqqueue Q;
    initque(Q);
    int n;
    cin >> n; // 输入命令的数量
    
    while (n--) {
        int command, x;
        cin >> command; // 输入命令类型

        switch (command) {
            case 1:  // 入队操作
                cin >> x;
                if (!enqueue(Q, x)) {
                    cout << "队列满" << endl;  // 队列满时输出提示
                }
                break;

            case 2:  // 出队操作
                if (dequeue(Q, x)) {
                    cout << x << endl;  // 输出出队的元素
                } else {
                    cout << "no" << endl;  // 队列为空时输出提示
                }
                break;

            case 3:  // 查询队列大小
                cout << que_size(Q) << endl;
                break;
        }
    }
    return 0;
}

1.逆置队列

#include <iostream>
#include <stack>

using namespace std;

#define MAXSIZe 50  // 队列最大容量

// 队列的定义
typedef struct {
    int data[MAXSIZe];
    int front, rear;
} Queue;

// 栈的定义
typedef stack<int> Stack;

// 初始化队列
void init(Queue& q) {
    q.front = q.rear = 0;
}

// 判断队列是否为空
bool isempty(Queue& q) {
    return q.front == q.rear;
}

// 判断队列是否满
bool isfull(Queue& q) {
    return (q.rear + 1) % MAXSIZe == q.front;
}

// 入队
bool enqueue(Queue& q, int value) {
    if (isfull(q)) {
        return false;  // 队列满
    }
    q.data[q.rear] = value;
    q.rear = (q.rear + 1) % MAXSIZe;
    return true;
}

// 出队
bool dequeue(Queue& q, int& value) {
    if (isempty(q)) {
        return false;  // 队列空
    }
    value = q.data[q.front];
    q.front = (q.front + 1) % MAXSIZe;
    return true;
}

// 获取队列大小
int queuesize(Queue& q) {
    return (q.rear - q.front + MAXSIZe) % MAXSIZe;
}

// 显示队列
void showQueue(Queue& q) {
    if (isempty(q)) {
        cout << "队列为空" << endl;
        return;
    }
    int i = q.front;
    while (i != q.rear) {
        cout << q.data[i] << " ";
        i = (i + 1) % MAXSIZe;
    }
    cout << endl;
}

// 逆置队列
void reversequeue(Queue& q) {
    Stack s;
    int temp;

    // Step 1: 将队列中的所有元素压入栈
    while (!isempty(q)) {
        dequeue(q, temp);
        s.push(temp);
    }

    // Step 2: 将栈中的元素重新入队
    while (!s.empty()) {
        enqueue(q, s.top());
        s.pop();
    }
}

int main() {
    Queue q;
    init(q);

    // 向队列中添加元素
    enqueue(q, 1);
    enqueue(q, 2);
    enqueue(q, 3);
    enqueue(q, 4);
    enqueue(q, 5);

    // 显示队列
    cout << "原队列: ";
    showQueue(q);

    // 逆置队列
    reversequeue(q);

    // 显示逆置后的队列
    cout << "逆置后的队列: ";
    showQueue(q);

    return 0;
}

二叉树

遍历顺序

#include <iostream>
#include <queue>
using namespace std;

struct treenode 
{
    int val;
    treenode* left;
    treenode* right;
    treenode(int x) : val(x), left(NULL), right(NULL) {}
};

void preorder(treenode* cur)//前序遍历
{
    if (cur == NULL)return;
    cout << cur->val;
    preorder(cur->left);
    preorder(cur->right);
}

void inorder(treenode* cur)//中序遍历
{
    if (cur == NULL) return;
    inorder(cur->left);
    cout << cur->val;
    inorder(cur->right);
}

void postorder(treenode* cur)//后序遍历
{
    if (cur == NULL)return;
    postorder(cur->left);
    postorder(cur->right);
    cout << cur->val;
}

// 层序遍历(广度优先遍历)
void levelOrder(treenode* root) 
{
    if (root == NULL) return;

    queue<treenode*> q;  // 创建一个队列
    q.push(root);  // 将根节点入队

    while (!q.empty()) {
        treenode* cur = q.front();  // 访问队头元素
        q.pop();  // 出队
        cout << cur->val << " ";  // 访问节点

        // 将左子节点和右子节点入队
        if (cur->left) q.push(cur->left);
        if (cur->right) q.push(cur->right);
    }
}

int main()
{

    return 0;
}


1.树的深度

编写一个递归算法,实现的功能是:求二叉树的深度并返回。

有如下二叉树的存储结构:
typedef struct tnode
{
   DataType   data;   //结点数据域 
   struct  tnode  *lchild,*rchild; //左右孩子指针
}BTree; 
该函数原型说明为:int TreeDepth(BTree *T); //T是二叉树

函数

// 递归函数:计算二叉树的深度
int treeDepth(BTree *T) {
    if (T == NULL) {
        return 0;  // 空树的深度是 0
    }

    // 递归计算左子树和右子树的深度
    int leftDepth = treeDepth(T->lchild);
    int rightDepth = treeDepth(T->rchild);

    // 返回左右子树深度的较大值加 1
    return max(leftDepth, rightDepth) + 1;
}

完整代码

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

struct treenode
{
int val;
treenode* left;
treenode* right;
treenode(int x):val(x), left(NULL), right(NULL) {}
};
void preorder(treenode* cur)//前序遍历
{
if (cur == NULL)return;
cout << cur->val;
preorder(cur->left);
preorder(cur->right);
}

void inorder(treenode* cur)//中序遍历
{
if (cur == NULL)return;
inorder(cur->left);
cout << cur->val;
inorder(cur->right);
}

void postorder(treenode* cur)//后序遍历
{
if (cur == NULL)return;
postorder(cur->left);
postorder(cur->right);
cout << cur->val;
}

// 层序遍历(广度优先遍历)
void levelOrder(treenode* root)
{
if (root == NULL)
{
return;
}
queue<treenode*> q;
q.push(root);

while (!q.empty())
{
treenode* cur = q.front();
q.pop();
cout << cur->val << " ";

if (cur->left)q.push(cur->left);
if (cur->right)q.push(cur->right);
}
}

int treedepth(treenode* root)
{

if (root == NULL)return 0;// 空树的深度是 0

// 递归计算左子树和右子树的深度
int leftdepth = treedepth(root->left);
int rightdepth = treedepth(root->right);

// 返回左右子树深度的较大值加 1
return max(leftdepth, rightdepth) + 1;
}
int main()
{
// 创建一个简单的二叉树
//         1
//       /   \
    //      2     3
//     / \   / \
    //    4   5 6   7
treenode* root = new treenode(1);
root->left = new treenode(2);
root->right = new treenode(3);
root->left->left = new treenode(4);
root->left->right = new treenode(5);
root->right->left = new treenode(6);
root->right->right = new treenode(7);

cout << "层序遍历的结果为: ";
levelOrder(root);
cout << endl;

cout << "树的深度是:" << treedepth(root);

return 0;
}

2.左右子树交换

编写一个递归算法,实现的功能是:将二叉树中的每一个结点的左子树和右子树互换。

有如下二叉树的存储结构:
typedef struct tnode
{
   DataType   data;   //结点数据域 
   struct  tnode  *lchild,*rchild; //左右孩子指针
}BTree; 
该函数原型说明为:void exchange(BTree *T);

函数

// 递归函数:交换二叉树的每个节点的左右子树
void exchange(BTree *T) {
    if (T == NULL) {
        return;  // 如果节点为空,直接返回
    }

    // 交换当前节点的左右子树
    BTree *temp = T->lchild;
    T->lchild = T->rchild;
    T->rchild = temp;

    // 递归交换左右子树
    exchange(T->lchild);
    exchange(T->rchild);
}

完整代码

#include <iostream>
#include <queue>
using namespace std;

struct treenode
{
int val;
treenode* left;
treenode* right;
treenode(int x):val(x), left(NULL), right(NULL) {}
};
void preorder(treenode* cur)//前序遍历
{
if (cur == NULL)return;
cout << cur->val;
preorder(cur->left);
preorder(cur->right);
}

void inorder(treenode* cur)//中序遍历
{
if (cur == NULL)return;
inorder(cur->left);
cout << cur->val;
inorder(cur->right);
}

void postorder(treenode* cur)//后序遍历
{
if (cur == NULL)return;
postorder(cur->left);
postorder(cur->right);
cout << cur->val;
}

// 层序遍历(广度优先遍历)
void levelOrder(treenode* root)
{
if (root == NULL)
{
return;
}
queue<treenode*> q;
q.push(root);

while (!q.empty())
{
treenode* cur = q.front();
q.pop();
cout << cur->val << " ";

if (cur->left)q.push(cur->left);
if (cur->right)q.push(cur->right);
}
}
void exchange(treenode* root)
{
if (root == NULL)
return;

// 交换当前节点的左右子树
treenode* temp = root->left;
root->left = root->right;
root->right = temp;

// 递归交换左子树和右子树
exchange(root->left);
exchange(root->right);
}

int main()
{
// 创建一个简单的二叉树
//         1
//       /   \
    //      2     3
//     / \   / \
    //    4   5 6   7
treenode* root = new treenode(1);
root->left = new treenode(2);
root->right = new treenode(3);
root->left->left = new treenode(4);
root->left->right = new treenode(5);
root->right->left = new treenode(6);
root->right->right = new treenode(7);

cout << "层序遍历的结果为: ";
levelOrder(root);
cout << endl;

// 交换左右子树
exchange(root);

cout << "交换左右子树后层序遍历的结果为: ";
levelOrder(root);
cout << endl;


 //      1
 //     / \
 //    3   2
 //   / \ / \
 //  7  6 5  4

return 0;
}

3.输出并求出非叶子节点个数

编写一个算法,实现的功能是:输出二叉树中所有非叶子结点,并求出非叶子结点的个数返回。

有如下二叉树的存储结构:
typedef char DataType ;
typedef struct tnode
{
   DataType   data;   //结点数据域 
   struct  tnode  *lchild,*rchild; //左右孩子指针
}BTree; 
该函数原型说明为:int Nonleafnum(BTree *T);  //T是二叉树


函数

// 递归函数:计算并输出二叉树中的所有非叶子节点
int Nonleafnum(BTree *T) {
    if (T == NULL) {
        return 0;  // 空树没有非叶子节点
    }

    int count = 0;

    // 判断当前节点是否是非叶子节点
    if (T->lchild != NULL || T->rchild != NULL) {
        cout << T->data << " ";  // 输出非叶子结点
        count = 1;  // 当前结点是非叶子节点,计数为 1
    }

    // 递归计算左子树和右子树的非叶子结点数
    count += Nonleafnum(T->lchild);
    count += Nonleafnum(T->rchild);

    return count;  // 返回非叶子结点的总数
}

完整代码

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

struct treenode {
    int val;
    treenode* left;
    treenode* right;
    treenode(int x) : val(x), left(NULL), right(NULL) {}
};

// 前序遍历
void preorder(treenode* cur) {
    if (cur == NULL) return;
    cout << cur->val << " ";
    preorder(cur->left);
    preorder(cur->right);
}

// 中序遍历
void inorder(treenode* cur) {
    if (cur == NULL) return;
    inorder(cur->left);
    cout << cur->val << " ";
    inorder(cur->right);
}

// 后序遍历
void postorder(treenode* cur) {
    if (cur == NULL) return;
    postorder(cur->left);
    postorder(cur->right);
    cout << cur->val << " ";
}

// 层序遍历(广度优先遍历)
void levelOrder(treenode* root) {
    if (root == NULL) {
        return;
    }
    queue<treenode*> q;
    q.push(root);

    while (!q.empty()) {
        treenode* cur = q.front();
        q.pop();
        cout << cur->val << " ";

        if (cur->left) q.push(cur->left);
        if (cur->right) q.push(cur->right);
    }
}

// 求非叶子节点个数的函数
int Nonleafnum(treenode* T) {
    if (T == NULL) return 0;  // 空树没有非叶子节点

    int count = 0;

    // 判断当前节点是否是非叶子节点
    if (T->left != NULL || T->right != NULL) {
        count = 1;  // 当前节点是非叶子节点,计数为 1
    }

    // 递归计算左子树和右子树的非叶子节点数
    count += Nonleafnum(T->left);
    count += Nonleafnum(T->right);

    return count;  // 返回非叶子节点的总数
}

int main() {
    // 创建一个简单的二叉树
    //         1
    //       /   \
    //      2     3
    //     / \   / \
    //    4   5 6   7
    treenode* root = new treenode(1);
    root->left = new treenode(2);
    root->right = new treenode(3);
    root->left->left = new treenode(4);
    root->left->right = new treenode(5);
    root->right->left = new treenode(6);
    root->right->right = new treenode(7);

    // 层序遍历的结果
    cout << "层序遍历的结果为: ";
    levelOrder(root);
    cout << endl;

    // 输出非叶子节点个数
    int nonLeafCount = Nonleafnum(root);
    cout << "非叶子节点的个数是: " << nonLeafCount << endl;

    return 0;
}

1.邻接矩阵转换成临界表

1. 编写一个算法,实现的功能是:将无权无向图的邻接矩阵转换成邻接表。
有如下存储结构:
#define MAX 100 
typedef  struct 
{
int  n,e;        //顶点数、边数 
char  vexs[MAX];      //顶点数组 
int  edges[MAX][MAX]; //边的邻接矩阵
}MGraph;    //图的邻接矩阵类型 

typedef char VertexType ;
typedef  struct  node   //定义边表结点 
{
int adjvex;   //邻接点域 
struct node  *next; //指向下一个邻接点的指针域 
}EdgeNode;    //边表类型
typedef  struct  vexnode //定义顶点表结点 
{
VertexType  data;  //顶点域 
EdgeNode *firstedge;  //指向第一条边结点的指针域 
}VHeadNode;    //邻接表结点类型 
typedef  struct
{
VHeadNode  adjlist[MAX];  //邻接表结点数组 
int  n,e;    //顶点数、边数 
}AdjList;    //图的邻接表类型 

该函数原型说明为:AdjList *MatToList(MGraph g)  
//g是邻接矩阵,返回一个邻接表

函数

// 将邻接矩阵转换为邻接表
AdjList* MatToList(MGraph g) 
{
    int i, j;

    // 动态分配邻接表内存
    AdjList* adjlist = new AdjList;
    adjlist->n = g.n;
    adjlist->e = g.e;

    // 初始化邻接表的顶点数据和边表
    for (i = 0; i < g.n; i++) 
    {
        adjlist->adjlist[i].data = g.vexs[i];
        adjlist->adjlist[i].firstedge = NULL; // 初始化每个顶点的边表为空
    }

    // 遍历邻接矩阵,填充邻接表
    for (i = 0; i < g.n; i++) 
    {
        for (j = i + 1; j < g.n; j++) 
        { // 修改此处,j从i+1开始,确保只插入一次边
            if (g.edges[i][j] == 1) 
            {
                // 插入的边从 i 到 j
                EdgeNode* newEdge = new EdgeNode;
                newEdge->adjvex = j;
                newEdge->next = adjlist->adjlist[i].firstedge;
                adjlist->adjlist[i].firstedge = newEdge;

                // 插入的边从 j 到 i
                EdgeNode* newEdgeRev = new EdgeNode;
                newEdgeRev->adjvex = i;
                newEdgeRev->next = adjlist->adjlist[j].firstedge;
                adjlist->adjlist[j].firstedge = newEdgeRev;
            }
        }
    }

    return adjlist;
}

完整代码

#include <iostream>
using namespace std;

#define MAX 100
typedef struct 
{
    int n, e;        // 顶点数、边数 
    char vexs[MAX];  // 顶点数组 
    int edges[MAX][MAX]; // 邻接矩阵
} MGraph; // 图的邻接矩阵类型 

typedef char VertexType;

typedef struct node 
{ // 定义边表结点 
    int adjvex;      // 邻接点域 
    struct node* next; // 指向下一个邻接点的指针域 
} EdgeNode; // 边表类型

typedef struct vexnode { // 定义顶点表结点 
    VertexType data;     // 顶点域 
    EdgeNode* firstedge; // 指向第一条边结点的指针域 
} VHeadNode; // 邻接表结点类型 

typedef struct 
{
    VHeadNode adjlist[MAX]; // 邻接表结点数组 
    int n, e; // 顶点数、边数 
} AdjList; // 图的邻接表类型 

// 将邻接矩阵转换为邻接表
AdjList* MatToList(MGraph g) 
{
    int i, j;

    // 动态分配邻接表内存
    AdjList* adjlist = new AdjList;
    adjlist->n = g.n;
    adjlist->e = g.e;

    // 初始化邻接表的顶点数据和边表
    for (i = 0; i < g.n; i++) 
    {
        adjlist->adjlist[i].data = g.vexs[i];
        adjlist->adjlist[i].firstedge = NULL; // 初始化每个顶点的边表为空
    }

    // 遍历邻接矩阵,填充邻接表
    for (i = 0; i < g.n; i++) 
    {
        for (j = i + 1; j < g.n; j++) 
        { // 修改此处,j从i+1开始,确保只插入一次边
            if (g.edges[i][j] == 1) 
            {
                // 插入的边从 i 到 j
                EdgeNode* newEdge = new EdgeNode;
                newEdge->adjvex = j;
                newEdge->next = adjlist->adjlist[i].firstedge;
                adjlist->adjlist[i].firstedge = newEdge;

                // 插入的边从 j 到 i
                EdgeNode* newEdgeRev = new EdgeNode;
                newEdgeRev->adjvex = i;
                newEdgeRev->next = adjlist->adjlist[j].firstedge;
                adjlist->adjlist[j].firstedge = newEdgeRev;
            }
        }
    }

    return adjlist;
}

// 打印邻接表
void printAdjList(AdjList* adjList) 
{
    for (int i = 0; i < adjList->n; i++) 
    {
        cout << adjList->adjlist[i].data << ": "; // 打印顶点
        EdgeNode* p = adjList->adjlist[i].firstedge;
        while (p != NULL) 
        {
            cout << adjList->adjlist[p->adjvex].data << " "; // 打印邻接点
            p = p->next;
        }
        cout << endl;
    }
}

int main() 
{
    MGraph g = 
    {
        5, 6,
        {'A', 'B', 'C', 'D', 'E'},
        {
            {0, 1, 0, 1, 0},
            {1, 0, 1, 0, 1},
            {0, 1, 0, 1, 1},
            {1, 0, 1, 0, 0},
            {0, 1, 1, 0, 0}
        }
    };

    // 调用函数转换邻接矩阵为邻接表
    AdjList* adjList = MatToList(g);

    // 打印邻接表
    printAdjList(adjList);

    // 释放内存
    for (int i = 0; i < adjList->n; i++) 
    {
        EdgeNode* p = adjList->adjlist[i].firstedge;
        while (p != NULL) 
        {
            EdgeNode* temp = p;
            p = p->next;
            delete temp; // 释放边节点内存
        }
    }
    delete adjList; // 释放邻接表内存

    return 0;
}
//因为是从头部插入进去的,所以输出是
//A: D B
//B : E C A
//C : E D B
//D : C A
//E : C B

2.深度优先搜索

编写一个算法,实现的功能是:从某个顶点开始深度优先搜索用邻接表存储表示的图。
有如下存储结构:
#define MAX 100 
typedef char VertexType ;
typedef  struct  node   //定义边表结点 
{
int adjvex;   //邻接点域 
struct node  *next; //指向下一个邻接点的指针域 
}EdgeNode;    //边表类型
typedef  struct  vexnode //定义顶点表结点 
{
VertexType  data;  //顶点域 
EdgeNode *firstedge;  //指向第一条边结点的指针域 
}VHeadNode;    //邻接表结点类型 
typedef  struct
{
VHeadNode  adjlist[MAX];  //邻接表结点数组 
int  n,e;    //顶点数、边数 
}AdjList;    //图的邻接表类型 
int visited[MAX];   //标志顶点是否被访问过的数组
该函数原型说明为:void DFS(AdjList *g,int vi); 
//从顶点vi开始深度优先搜索用邻接表存储的图g

函数

int visited[MAX]; // 标志顶点是否被访问过的数组

// 深度优先搜索
void DFS(AdjList* g, int vi) {
    // 访问当前顶点
    cout << "Visited " << g->adjlist[vi].data << endl;
    visited[vi] = 1;  // 标记当前顶点为已访问

    // 遍历当前顶点的邻接点
    EdgeNode* p = g->adjlist[vi].firstedge;
    while (p) {
        int w = p->adjvex;  // 邻接点索引
        if (!visited[w]) {  // 如果邻接点未访问
            DFS(g, w);  // 递归访问邻接点
        }
        p = p->next;  // 移动到下一个邻接点
    }
}

完整代码

#include <iostream>
#include <cstdlib>

using namespace std;

#define MAX 100

typedef char VertexType;

// 定义边表结点
struct EdgeNode 
{
    int adjvex;           // 邻接点
    EdgeNode* next;      // 指向下一个邻接点的指针
};

// 定义顶点表结点
struct VHeadNode 
{
    VertexType data;     // 顶点数据
    EdgeNode* firstedge; // 指向第一条边的指针
};

// 邻接表类型
struct AdjList 
{
    VHeadNode adjlist[MAX]; // 邻接表数组
    int n, e;               // 图的顶点数和边数
};

int visited[MAX]; // 标志顶点是否被访问过的数组

// 深度优先搜索
void DFS(AdjList* g, int vi) {
    // 访问当前顶点
    cout << "Visited " << g->adjlist[vi].data << endl;
    visited[vi] = 1;  // 标记当前顶点为已访问

    // 遍历当前顶点的邻接点
    EdgeNode* p = g->adjlist[vi].firstedge;
    while (p) {
        int w = p->adjvex;  // 邻接点索引
        if (!visited[w]) {  // 如果邻接点未访问
            DFS(g, w);  // 递归访问邻接点
        }
        p = p->next;  // 移动到下一个邻接点
    }
}

int main() 
{
    AdjList* g = new AdjList;  // 使用 new 创建图的邻接表

    cout << "请输入图的顶点数和边数(例如:5 6): ";
    cin >> g->n >> g->e;

    // 初始化访问标志数组
    for (int i = 0; i < MAX; i++) 
    {
        visited[i] = 0;
    }

    // 初始化图的顶点
    cout << "请输入图的每个顶点数据(例如:A B C D E): ";
    for (int i = 0; i < g->n; i++) 
    {
        cin >> g->adjlist[i].data;
        g->adjlist[i].firstedge = NULL;  // 初始化邻接表为空
    }

    // 输入图的边
    cout << "请输入图的每条边(格式:起点 终点): " << endl;
    for (int i = 0; i < g->e; i++) 
    {
        char start, end;
        cin >> start >> end;
        int startIndex = -1, endIndex = -1;

        // 查找起点和终点的索引
        for (int j = 0; j < g->n; j++) 
        {
            if (g->adjlist[j].data == start) 
            {
                startIndex = j;
            }
            if (g->adjlist[j].data == end) 
            {
                endIndex = j;
            }
        }

        // 处理起点到终点的边
        if (startIndex != -1 && endIndex != -1) 
        {
            // 创建边表节点
            EdgeNode* eNode = new EdgeNode;
            eNode->adjvex = endIndex;
            eNode->next = g->adjlist[startIndex].firstedge;
            g->adjlist[startIndex].firstedge = eNode;
        }
    }

    // 从顶点0(假设A)开始深度优先搜索
    cout << "从顶点 " << g->adjlist[0].data << " 开始深度优先搜索:" << endl;
    DFS(g, 0);

    // 释放动态分配的内存
    delete g;

    return 0;
}

查找

折半查找算法

 编写一个折半查找递归算法,实现功能是:递归折半查找关键字为k的位置并返回,若找到则返回相应位置,找不到则返回-1。
有如下折半查找的线性表结构:
typedef int KeyType;
typedef struct
{
KeyType key;
}SearchL;
该函数原型说明为:int BSearch(SearchL r[],KeyType k,int low,int high); 
//r为线性表,k为查找关键字,low, high分别是低位下标和高位下标

函数

int BSearch(SearchL r[], KeyType k, int low, int high)
{
if (low > high)
{
return -1;
}
int mid = (low+high) / 2;

if (r[mid].key == k)
{
return mid;
}
else if (r[mid].key > k)
{
return BSearch(r, k, low, mid - 1);
}
else
{
return BSearch(r, k, mid + 1, high);
}
}

完整代码

#include <iostream>
using namespace std;
const  int N = 100;
typedef int KeyType;

typedef struct
{
KeyType key;

}SearchL;

int BSearch(SearchL r[], KeyType k, int low, int high)
{
if (low > high)
{
return -1;
}
int mid = (low+high) / 2;

if (r[mid].key == k)
{
return mid;
}
else if (r[mid].key > k)
{
return BSearch(r, k, low, mid - 1);
}
else
{
return BSearch(r, k, mid + 1, high);
}
}

int main()
{
int n;
cout << "请输入线性表的大小: ";
cin >> n;

SearchL r[N];

cout << "请输入线性中元素(按顺序输入):";
for(int i=0;i<n;i++)
{
cin >> r[i].key;
}

KeyType k;
cout << "请输入要查找的关键字:";
cin >> k;

int result = BSearch(r, k, 0, n - 1);

if (result != -1)
{
cout << "关键字" << k << "的位置是:" << result<<endl;
}
else
{
cout << "关键字" << k << "不存在于线性表中"<<endl;
}

return 0;
}

排序

快速排序

 编写一个快速排序算法,实现功能是:用快速排序算法对排序表中的记录按关键字key进行从小到大排序。
有如下排序记录的存储结构:
typedef int KeyType;
typedef struct
{
KeyType key;
}LineList;
该函数原型说明为:void QuickSort(LineList r[],int low,int high); 
//r为排序表,low, high分别是低位下标和高位下标

函数

// 交换两个元素的位置
void Swap(LineList& a, LineList& b) {
    LineList temp = a;
    a = b;
    b = temp;
}

// 快速排序算法(将分区函数合并进来)
void QuickSort(LineList r[], int low, int high) {
    if (low < high) {
        // 选择基准元素,通常选择中间的元素
        int pivot = r[(low + high) / 2].key;
        int i = low - 1;  // i 表示小于基准元素的部分的最后一个元素的索引
        int j = high + 1;  // j 表示大于基准元素的部分的第一个元素的索引

        // 分区操作
        while (true) {
            // 寻找第一个大于或等于基准的元素
            do i++; while (r[i].key < pivot);

            // 寻找第一个小于或等于基准的元素
            do j--; while (r[j].key > pivot);

            // 如果 i < j, 则交换 r[i] 和 r[j]
            if (i < j) {
                Swap(r[i], r[j]);
            }
            else {
                // 否则返回 j 作为基准的位置
                break;
            }
        }

        // 递归地对基准元素左侧和右侧的部分进行快速排序
        QuickSort(r, low, j);
        QuickSort(r, j + 1, high);
    }
}

完整代码

#include <iostream>
using namespace std;

const int N = 100;
typedef int KeyType;

typedef struct {
    KeyType key;
} LineList;

// 交换两个元素的位置
void Swap(LineList& a, LineList& b) {
    LineList temp = a;
    a = b;
    b = temp;
}

// 快速排序算法(将分区函数合并进来)
void QuickSort(LineList r[], int low, int high) {
    if (low < high) {
        // 选择基准元素,通常选择中间的元素
        int pivot = r[(low + high) / 2].key;
        int i = low - 1;  // i 表示小于基准元素的部分的最后一个元素的索引
        int j = high + 1;  // j 表示大于基准元素的部分的第一个元素的索引

        // 分区操作
        while (true) {
            // 寻找第一个大于或等于基准的元素
            do i++; while (r[i].key < pivot);

            // 寻找第一个小于或等于基准的元素
            do j--; while (r[j].key > pivot);

            // 如果 i < j, 则交换 r[i] 和 r[j]
            if (i < j) {
                Swap(r[i], r[j]);
            }
            else {
                // 否则返回 j 作为基准的位置
                break;
            }
        }

        // 递归地对基准元素左侧和右侧的部分进行快速排序
        QuickSort(r, low, j);
        QuickSort(r, j + 1, high);
    }
}

// 输出排序后的数组
void PrintArray(LineList r[], int n) {
    for (int i = 0; i < n; i++) {
        cout << r[i].key << " ";
    }
    cout << endl;
}

int main() {
    int n;
    cout << "请输入排序表的大小: ";
    cin >> n;

    LineList r[N];  // 创建排序表

    cout << "请输入排序表中的元素(按顺序输入):";
    for (int i = 0; i < n; i++) {
        cin >> r[i].key;
    }

    // 调用快速排序
    QuickSort(r, 0, n - 1);

    // 输出排序后的数组
    cout << "排序后的元素为:";
    PrintArray(r, n);

    return 0;
}


原文地址:https://blog.csdn.net/2301_79758400/article/details/144252328

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!